aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/access.c4
-rw-r--r--drivers/pci/hotplug/acpiphp.h1
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c63
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c54
-rw-r--r--drivers/pci/htirq.c5
-rw-r--r--drivers/pci/intel-iommu.c22
-rw-r--r--drivers/pci/intr_remapping.c54
-rw-r--r--drivers/pci/msi.c8
-rw-r--r--drivers/pci/pci-sysfs.c12
-rw-r--r--drivers/pci/pci.c73
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h3
-rw-r--r--drivers/pci/pcie/portdrv_pci.c2
-rw-r--r--drivers/pci/probe.c8
-rw-r--r--drivers/pci/quirks.c1
-rw-r--r--drivers/pci/setup-bus.c6
-rw-r--r--drivers/pci/slot.c4
16 files changed, 185 insertions, 135 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 64dd7df90e6..0f370651268 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -87,8 +87,8 @@ EXPORT_SYMBOL(pci_read_vpd);
* pci_write_vpd - Write entry to Vital Product Data
* @dev: pci device struct
* @pos: offset in vpd space
- * @count: number of bytes to read
- * @val: value to write
+ * @count: number of bytes to write
+ * @buf: buffer containing write data
*
*/
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 4fc168b7009..e68d5f20ffb 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -129,7 +129,6 @@ struct acpiphp_func {
struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */
struct list_head sibling;
- struct pci_dev *pci_dev;
struct notifier_block nb;
acpi_handle handle;
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index a33794d9e0d..3a6064bce56 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -32,9 +32,6 @@
/*
* Lifetime rules for pci_dev:
- * - The one in acpiphp_func has its refcount elevated by pci_get_slot()
- * when the driver is loaded or when an insertion event occurs. It loses
- * a refcount when its ejected or the driver unloads.
* - 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.
@@ -130,6 +127,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
unsigned long long adr, sun;
int device, function, retval;
struct pci_bus *pbus = bridge->pci_bus;
+ struct pci_dev *pdev;
if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
return AE_OK;
@@ -213,10 +211,10 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
newfunc->slot = slot;
list_add_tail(&newfunc->sibling, &slot->funcs);
- /* associate corresponding pci_dev */
- newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function));
- if (newfunc->pci_dev) {
+ pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
+ if (pdev) {
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+ pci_dev_put(pdev);
}
if (is_dock_device(handle)) {
@@ -617,7 +615,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
- pci_dev_put(func->pci_dev);
list_del(list);
kfree(func);
}
@@ -1101,22 +1098,24 @@ static int __ref enable_device(struct acpiphp_slot *slot)
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
- /* associate pci_dev to our representation */
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
- func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
- func->function));
- if (!func->pci_dev)
+ dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
+ func->function));
+ if (!dev)
continue;
- if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
- func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
+ if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
+ dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
+ pci_dev_put(dev);
continue;
+ }
status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge failed (error code = 0x%x)\n",
status);
+ pci_dev_put(dev);
}
slot->flags |= SLOT_ENABLED;
@@ -1142,17 +1141,14 @@ static void disable_bridges(struct pci_bus *bus)
*/
static int disable_device(struct acpiphp_slot *slot)
{
- int retval = 0;
struct acpiphp_func *func;
- struct list_head *l;
+ struct pci_dev *pdev;
/* is this slot already disabled? */
if (!(slot->flags & SLOT_ENABLED))
goto err_exit;
- list_for_each (l, &slot->funcs) {
- func = list_entry(l, struct acpiphp_func, sibling);
-
+ list_for_each_entry(func, &slot->funcs, sibling) {
if (func->bridge) {
/* cleanup p2p bridges under this P2P bridge */
cleanup_p2p_bridge(func->bridge->handle,
@@ -1160,35 +1156,28 @@ static int disable_device(struct acpiphp_slot *slot)
func->bridge = NULL;
}
- if (func->pci_dev) {
- pci_stop_bus_device(func->pci_dev);
- if (func->pci_dev->subordinate) {
- disable_bridges(func->pci_dev->subordinate);
- pci_disable_device(func->pci_dev);
+ pdev = pci_get_slot(slot->bridge->pci_bus,
+ PCI_DEVFN(slot->device, func->function));
+ if (pdev) {
+ pci_stop_bus_device(pdev);
+ if (pdev->subordinate) {
+ disable_bridges(pdev->subordinate);
+ pci_disable_device(pdev);
}
+ pci_remove_bus_device(pdev);
+ pci_dev_put(pdev);
}
}
- list_for_each (l, &slot->funcs) {
- func = list_entry(l, struct acpiphp_func, sibling);
-
+ list_for_each_entry(func, &slot->funcs, sibling) {
acpiphp_unconfigure_ioapics(func->handle);
acpiphp_bus_trim(func->handle);
- /* try to remove anyway.
- * acpiphp_bus_add might have been failed */
-
- if (!func->pci_dev)
- continue;
-
- pci_remove_bus_device(func->pci_dev);
- pci_dev_put(func->pci_dev);
- func->pci_dev = NULL;
}
slot->flags &= (~SLOT_ENABLED);
- err_exit:
- return retval;
+err_exit:
+ return 0;
}
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index dd18f857dfb..42e4260c3b1 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -153,45 +153,47 @@ int ibmphp_init_devno(struct slot **cur_slot)
return -1;
}
for (loop = 0; loop < len; loop++) {
- if ((*cur_slot)->number == rtable->slots[loop].slot) {
- if ((*cur_slot)->bus == rtable->slots[loop].bus) {
+ if ((*cur_slot)->number == rtable->slots[loop].slot &&
+ (*cur_slot)->bus == rtable->slots[loop].bus) {
+ struct io_apic_irq_attr irq_attr;
+
(*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn);
for (i = 0; i < 4; i++)
(*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus,
- (int) (*cur_slot)->device, i);
-
- debug("(*cur_slot)->irq[0] = %x\n",
- (*cur_slot)->irq[0]);
- debug("(*cur_slot)->irq[1] = %x\n",
- (*cur_slot)->irq[1]);
- debug("(*cur_slot)->irq[2] = %x\n",
- (*cur_slot)->irq[2]);
- debug("(*cur_slot)->irq[3] = %x\n",
- (*cur_slot)->irq[3]);
-
- debug("rtable->exlusive_irqs = %x\n",
+ (int) (*cur_slot)->device, i,
+ &irq_attr);
+
+ debug("(*cur_slot)->irq[0] = %x\n",
+ (*cur_slot)->irq[0]);
+ debug("(*cur_slot)->irq[1] = %x\n",
+ (*cur_slot)->irq[1]);
+ debug("(*cur_slot)->irq[2] = %x\n",
+ (*cur_slot)->irq[2]);
+ debug("(*cur_slot)->irq[3] = %x\n",
+ (*cur_slot)->irq[3]);
+
+ debug("rtable->exlusive_irqs = %x\n",
rtable->exclusive_irqs);
- debug("rtable->slots[loop].irq[0].bitmap = %x\n",
+ debug("rtable->slots[loop].irq[0].bitmap = %x\n",
rtable->slots[loop].irq[0].bitmap);
- debug("rtable->slots[loop].irq[1].bitmap = %x\n",
+ debug("rtable->slots[loop].irq[1].bitmap = %x\n",
rtable->slots[loop].irq[1].bitmap);
- debug("rtable->slots[loop].irq[2].bitmap = %x\n",
+ debug("rtable->slots[loop].irq[2].bitmap = %x\n",
rtable->slots[loop].irq[2].bitmap);
- debug("rtable->slots[loop].irq[3].bitmap = %x\n",
+ debug("rtable->slots[loop].irq[3].bitmap = %x\n",
rtable->slots[loop].irq[3].bitmap);
- debug("rtable->slots[loop].irq[0].link = %x\n",
+ debug("rtable->slots[loop].irq[0].link = %x\n",
rtable->slots[loop].irq[0].link);
- debug("rtable->slots[loop].irq[1].link = %x\n",
+ debug("rtable->slots[loop].irq[1].link = %x\n",
rtable->slots[loop].irq[1].link);
- debug("rtable->slots[loop].irq[2].link = %x\n",
+ debug("rtable->slots[loop].irq[2].link = %x\n",
rtable->slots[loop].irq[2].link);
- debug("rtable->slots[loop].irq[3].link = %x\n",
+ debug("rtable->slots[loop].irq[3].link = %x\n",
rtable->slots[loop].irq[3].link);
- debug("end of init_devno\n");
- kfree(rtable);
- return 0;
- }
+ debug("end of init_devno\n");
+ kfree(rtable);
+ return 0;
}
}
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index bf7d6ce9bbb..737a1c44b07 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -98,6 +98,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
int max_irq;
int pos;
int irq;
+ int node;
pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
if (!pos)
@@ -125,7 +126,8 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
cfg->msg.address_lo = 0xffffffff;
cfg->msg.address_hi = 0xffffffff;
- irq = create_irq();
+ node = dev_to_node(&dev->dev);
+ irq = create_irq_nr(0, node);
if (irq <= 0) {
kfree(cfg);
@@ -158,6 +160,7 @@ int ht_create_irq(struct pci_dev *dev, int idx)
/**
* ht_destroy_irq - destroy an irq created with ht_create_irq
+ * @irq: irq to be destroyed
*
* This reverses ht_create_irq removing the specified irq from
* existence. The irq should be free before this happens.
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 001b328adf8..cd389162735 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -59,6 +59,10 @@
#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
+#ifndef PHYSICAL_PAGE_MASK
+#define PHYSICAL_PAGE_MASK PAGE_MASK
+#endif
+
/* global iommu list, set NULL for ignored DMAR units */
static struct intel_iommu **g_iommus;
@@ -1216,7 +1220,7 @@ static void dmar_init_reserved_ranges(void)
if (!r->flags || !(r->flags & IORESOURCE_MEM))
continue;
addr = r->start;
- addr &= PAGE_MASK;
+ addr &= PHYSICAL_PAGE_MASK;
size = r->end - addr;
size = PAGE_ALIGN(size);
iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
@@ -1968,15 +1972,6 @@ static int __init init_dmars(void)
}
}
-#ifdef CONFIG_INTR_REMAP
- if (!intr_remapping_enabled) {
- ret = enable_intr_remapping(0);
- if (ret)
- printk(KERN_ERR
- "IOMMU: enable interrupt remapping failed\n");
- }
-#endif
-
/*
* For each rmrr
* for each dev attached to rmrr
@@ -2173,7 +2168,8 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
* is not a big problem
*/
ret = domain_page_mapping(domain, start_paddr,
- ((u64)paddr) & PAGE_MASK, size, prot);
+ ((u64)paddr) & PHYSICAL_PAGE_MASK,
+ size, prot);
if (ret)
goto error;
@@ -2463,8 +2459,8 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
addr = page_to_phys(sg_page(sg)) + sg->offset;
size = aligned_size((u64)addr, sg->length);
ret = domain_page_mapping(domain, start_addr + offset,
- ((u64)addr) & PAGE_MASK,
- size, prot);
+ ((u64)addr) & PHYSICAL_PAGE_MASK,
+ size, prot);
if (ret) {
/* clear the page */
dma_pte_clear_range(domain, start_addr,
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c
index f5e0ea724a6..3a0cb0bb059 100644
--- a/drivers/pci/intr_remapping.c
+++ b/drivers/pci/intr_remapping.c
@@ -15,6 +15,14 @@ static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
static int ir_ioapic_num;
int intr_remapping_enabled;
+static int disable_intremap;
+static __init int setup_nointremap(char *str)
+{
+ disable_intremap = 1;
+ return 0;
+}
+early_param("nointremap", setup_nointremap);
+
struct irq_2_iommu {
struct intel_iommu *iommu;
u16 irte_index;
@@ -23,15 +31,12 @@ struct irq_2_iommu {
};
#ifdef CONFIG_GENERIC_HARDIRQS
-static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
+static struct irq_2_iommu *get_one_free_irq_2_iommu(int node)
{
struct irq_2_iommu *iommu;
- int node;
-
- node = cpu_to_node(cpu);
iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
- printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
+ printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node);
return iommu;
}
@@ -48,7 +53,7 @@ static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
return desc->irq_2_iommu;
}
-static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
+static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node)
{
struct irq_desc *desc;
struct irq_2_iommu *irq_iommu;
@@ -56,7 +61,7 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
/*
* alloc irq desc if not allocated already.
*/
- desc = irq_to_desc_alloc_cpu(irq, cpu);
+ desc = irq_to_desc_alloc_node(irq, node);
if (!desc) {
printk(KERN_INFO "can not get irq_desc for %d\n", irq);
return NULL;
@@ -65,14 +70,14 @@ static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
irq_iommu = desc->irq_2_iommu;
if (!irq_iommu)
- desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu);
+ desc->irq_2_iommu = get_one_free_irq_2_iommu(node);
return desc->irq_2_iommu;
}
static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
{
- return irq_2_iommu_alloc_cpu(irq, boot_cpu_id);
+ return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id));
}
#else /* !CONFIG_SPARSE_IRQ */
@@ -423,20 +428,6 @@ static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
readl, (sts & DMA_GSTS_IRTPS), sts);
spin_unlock_irqrestore(&iommu->register_lock, flags);
- if (mode == 0) {
- spin_lock_irqsave(&iommu->register_lock, flags);
-
- /* enable comaptiblity format interrupt pass through */
- cmd = iommu->gcmd | DMA_GCMD_CFI;
- iommu->gcmd |= DMA_GCMD_CFI;
- writel(cmd, iommu->reg + DMAR_GCMD_REG);
-
- IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
- readl, (sts & DMA_GSTS_CFIS), sts);
-
- spin_unlock_irqrestore(&iommu->register_lock, flags);
- }
-
/*
* global invalidation of interrupt entry cache before enabling
* interrupt-remapping.
@@ -516,6 +507,23 @@ end:
spin_unlock_irqrestore(&iommu->register_lock, flags);
}
+int __init intr_remapping_supported(void)
+{
+ struct dmar_drhd_unit *drhd;
+
+ if (disable_intremap)
+ return 0;
+
+ for_each_drhd_unit(drhd) {
+ struct intel_iommu *iommu = drhd->iommu;
+
+ if (!ecap_ir_support(iommu->ecap))
+ return 0;
+ }
+
+ return 1;
+}
+
int __init enable_intr_remapping(int eim)
{
struct dmar_drhd_unit *drhd;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 6f2e6295e77..362773247fb 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -455,8 +455,6 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.default_irq = dev->irq;
entry->msi_attrib.pos = pos;
entry->mask_base = base;
- entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
msix_mask_irq(entry, 1);
list_add_tail(&entry->list, &dev->msi_list);
@@ -493,6 +491,12 @@ static int msix_capability_init(struct pci_dev *dev,
msix_set_enable(dev, 1);
dev->msix_enabled = 1;
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ int vector = entry->msi_attrib.entry_nr;
+ entry->masked = readl(base + vector * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+ }
+
return 0;
}
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a7eb1b46a5a..85ebd02a64a 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -492,6 +492,7 @@ write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
/**
* pci_read_legacy_io - read byte(s) from legacy I/O port space
* @kobj: kobject corresponding to file to read from
+ * @bin_attr: struct bin_attribute for this file
* @buf: buffer to store results
* @off: offset into legacy I/O port space
* @count: number of bytes to read
@@ -517,6 +518,7 @@ pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
/**
* pci_write_legacy_io - write byte(s) to legacy I/O port space
* @kobj: kobject corresponding to file to read from
+ * @bin_attr: struct bin_attribute for this file
* @buf: buffer containing value to be written
* @off: offset into legacy I/O port space
* @count: number of bytes to write
@@ -733,9 +735,9 @@ pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr,
/**
* pci_remove_resource_files - cleanup resource files
- * @dev: dev to cleanup
+ * @pdev: dev to cleanup
*
- * If we created resource files for @dev, remove them from sysfs and
+ * If we created resource files for @pdev, remove them from sysfs and
* free their resources.
*/
static void
@@ -793,9 +795,9 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
/**
* pci_create_resource_files - create resource files in sysfs for @dev
- * @dev: dev in question
+ * @pdev: dev in question
*
- * Walk the resources in @dev creating files for each resource available.
+ * Walk the resources in @pdev creating files for each resource available.
*/
static int pci_create_resource_files(struct pci_dev *pdev)
{
@@ -829,6 +831,7 @@ void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
/**
* pci_write_rom - used to enable access to the PCI ROM display
* @kobj: kernel object handle
+ * @bin_attr: struct bin_attribute for this file
* @buf: user input
* @off: file offset
* @count: number of byte in input
@@ -852,6 +855,7 @@ pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
/**
* pci_read_rom - read a PCI ROM
* @kobj: kernel object handle
+ * @bin_attr: struct bin_attribute for this file
* @buf: where to put the data we read from the ROM
* @off: file offset
* @count: number of bytes to read
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 16fd0d4c316..1a91bf9687a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -557,7 +557,8 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
} else {
error = -ENODEV;
/* Fall back to PCI_D0 if native PM is not supported */
- pci_update_current_state(dev, PCI_D0);
+ if (!dev->pm_cap)
+ dev->current_state = PCI_D0;
}
return error;
@@ -681,11 +682,34 @@ EXPORT_SYMBOL(pci_choose_state);
#define PCI_EXP_SAVE_REGS 7
+#define pcie_cap_has_devctl(type, flags) 1
+#define pcie_cap_has_lnkctl(type, flags) \
+ ((flags & PCI_EXP_FLAGS_VERS) > 1 || \
+ (type == PCI_EXP_TYPE_ROOT_PORT || \
+ type == PCI_EXP_TYPE_ENDPOINT || \
+ type == PCI_EXP_TYPE_LEG_END))
+#define pcie_cap_has_sltctl(type, flags) \
+ ((flags & PCI_EXP_FLAGS_VERS) > 1 || \
+ ((type == PCI_EXP_TYPE_ROOT_PORT) || \
+ (type == PCI_EXP_TYPE_DOWNSTREAM && \
+ (flags & PCI_EXP_FLAGS_SLOT))))
+#define pcie_cap_has_rtctl(type, flags) \
+ ((flags & PCI_EXP_FLAGS_VERS) > 1 || \
+ (type == PCI_EXP_TYPE_ROOT_PORT || \
+ type == PCI_EXP_TYPE_RC_EC))
+#define pcie_cap_has_devctl2(type, flags) \
+ ((flags & PCI_EXP_FLAGS_VERS) > 1)
+#define pcie_cap_has_lnkctl2(type, flags) \
+ ((flags & PCI_EXP_FLAGS_VERS) > 1)
+#define pcie_cap_has_sltctl2(type, flags) \
+ ((flags & PCI_EXP_FLAGS_VERS) > 1)
+
static int pci_save_pcie_state(struct pci_dev *dev)
{
int pos, i = 0;
struct pci_cap_saved_state *save_state;
u16 *cap;
+ u16 flags;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (pos <= 0)
@@ -698,13 +722,22 @@ static int pci_save_pcie_state(struct pci_dev *dev)
}
cap = (u16 *)&save_state->data[0];
- pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
- pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
- pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
- pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
- pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
- pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
- pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
+
+ if (pcie_cap_has_devctl(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
+ if (pcie_cap_has_lnkctl(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
+ if (pcie_cap_has_sltctl(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
+ if (pcie_cap_has_rtctl(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
+ if (pcie_cap_has_devctl2(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]);
+ if (pcie_cap_has_lnkctl2(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]);
+ if (pcie_cap_has_sltctl2(dev->pcie_type, flags))
+ pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]);
return 0;
}
@@ -714,6 +747,7 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
int i = 0, pos;
struct pci_cap_saved_state *save_state;
u16 *cap;
+ u16 flags;
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
@@ -721,13 +755,22 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
return;
cap = (u16 *)&save_state->data[0];
- pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
- pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
- pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
- pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
- pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
- pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
- pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
+
+ if (pcie_cap_has_devctl(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
+ if (pcie_cap_has_lnkctl(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
+ if (pcie_cap_has_sltctl(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
+ if (pcie_cap_has_rtctl(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
+ if (pcie_cap_has_devctl2(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]);
+ if (pcie_cap_has_lnkctl2(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]);
+ if (pcie_cap_has_sltctl2(dev->pcie_type, flags))
+ pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]);
}
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index c7ad68b6c6d..aa14482a477 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -95,6 +95,9 @@ struct aer_broadcast_data {
static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
enum pci_ers_result new)
{
+ if (new == PCI_ERS_RESULT_NONE)
+ return orig;
+
switch (orig) {
case PCI_ERS_RESULT_CAN_RECOVER:
case PCI_ERS_RESULT_RECOVERED:
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index b924e2463f8..091ce70051e 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -200,7 +200,7 @@ static int slot_reset_iter(struct device *device, void *data)
static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
{
- pci_ers_result_t status = PCI_ERS_RESULT_NONE;
+ pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
int retval;
/* If fatal, restore cfg space for possible link reset at upstream */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8eb50dffb78..f1ae2475fff 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -745,6 +745,8 @@ int pci_setup_device(struct pci_dev *dev)
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
+ /* device class may be changed after fixup */
+ class = dev->class >> 8;
switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
@@ -1118,10 +1120,6 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
return max;
}
-void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b)
-{
-}
-
struct pci_bus * pci_create_bus(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
@@ -1180,8 +1178,6 @@ struct pci_bus * pci_create_bus(struct device *parent,
b->resource[0] = &ioport_resource;
b->resource[1] = &iomem_resource;
- set_pci_bus_resources_arch_default(b);
-
return b;
dev_create_file_err:
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 0254741bece..3067673d54f 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2033,6 +2033,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_di
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
static void __devinit quirk_disable_msi(struct pci_dev *dev)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8d9da9d30a6..a00f85471b6 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -536,11 +536,13 @@ static void pci_bus_dump_res(struct pci_bus *bus)
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
struct resource *res = bus->resource[i];
- if (!res)
+ if (!res || !res->end)
continue;
dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i,
- (res->flags & IORESOURCE_IO) ? "io: " : "mem:", res);
+ (res->flags & IORESOURCE_IO) ? "io: " :
+ ((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"),
+ res);
}
}
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index 21189447e54..fe95ce20bcb 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -264,8 +264,8 @@ EXPORT_SYMBOL_GPL(pci_create_slot);
/**
* pci_renumber_slot - update %struct pci_slot -> number
- * @slot - %struct pci_slot to update
- * @slot_nr - new number for slot
+ * @slot: &struct pci_slot to update
+ * @slot_nr: new number for slot
*
* The primary purpose of this interface is to allow callers who earlier
* created a placeholder slot in pci_create_slot() by passing a -1 as