diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/intel-iommu.c | 6 | ||||
-rw-r--r-- | drivers/pci/intr_remapping.c | 76 | ||||
-rw-r--r-- | drivers/pci/msi.c | 55 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 15 | ||||
-rw-r--r-- | drivers/pci/pci.c | 6 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 29 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 17 | ||||
-rw-r--r-- | drivers/pci/slot.c | 1 |
8 files changed, 171 insertions, 34 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index a2692724b68..5c8baa43ac9 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1655,12 +1655,14 @@ int __init init_dmars(void) iommu->flush.flush_context = __iommu_flush_context; iommu->flush.flush_iotlb = __iommu_flush_iotlb; printk(KERN_INFO "IOMMU 0x%Lx: using Register based " - "invalidation\n", drhd->reg_base_addr); + "invalidation\n", + (unsigned long long)drhd->reg_base_addr); } else { iommu->flush.flush_context = qi_flush_context; iommu->flush.flush_iotlb = qi_flush_iotlb; printk(KERN_INFO "IOMMU 0x%Lx: using Queued " - "invalidation\n", drhd->reg_base_addr); + "invalidation\n", + (unsigned long long)drhd->reg_base_addr); } } diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 2de5a3238c9..c9958ec5e25 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -19,17 +19,75 @@ struct irq_2_iommu { u8 irte_mask; }; -static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; +#ifdef CONFIG_SPARSE_IRQ +static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu) +{ + 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); + + return iommu; +} static struct irq_2_iommu *irq_2_iommu(unsigned int irq) { - return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL; + struct irq_desc *desc; + + desc = irq_to_desc(irq); + + if (WARN_ON_ONCE(!desc)) + return NULL; + + return desc->irq_2_iommu; +} + +static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu) +{ + struct irq_desc *desc; + struct irq_2_iommu *irq_iommu; + + /* + * alloc irq desc if not allocated already. + */ + desc = irq_to_desc_alloc_cpu(irq, cpu); + if (!desc) { + printk(KERN_INFO "can not get irq_desc for %d\n", irq); + return NULL; + } + + irq_iommu = desc->irq_2_iommu; + + if (!irq_iommu) + desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu); + + 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); +} + +#else /* !CONFIG_SPARSE_IRQ */ + +static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; + +static struct irq_2_iommu *irq_2_iommu(unsigned int irq) +{ + if (irq < nr_irqs) + return &irq_2_iommuX[irq]; + + return NULL; +} +static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) +{ return irq_2_iommu(irq); } +#endif static DEFINE_SPINLOCK(irq_2_ir_lock); @@ -86,9 +144,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) if (!count) return -1; +#ifndef CONFIG_SPARSE_IRQ /* protect irq_2_iommu_alloc later */ if (irq >= nr_irqs) return -1; +#endif /* * start the IRTE search from index 0. @@ -130,6 +190,12 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) table->base[i].present = 1; irq_iommu = irq_2_iommu_alloc(irq); + if (!irq_iommu) { + spin_unlock(&irq_2_ir_lock); + printk(KERN_ERR "can't allocate irq_2_iommu\n"); + return -1; + } + irq_iommu->iommu = iommu; irq_iommu->irte_index = index; irq_iommu->sub_handle = 0; @@ -177,6 +243,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) irq_iommu = irq_2_iommu_alloc(irq); + if (!irq_iommu) { + spin_unlock(&irq_2_ir_lock); + printk(KERN_ERR "can't allocate irq_2_iommu\n"); + return -1; + } + irq_iommu->iommu = iommu; irq_iommu->irte_index = index; irq_iommu->sub_handle = subhandle; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 74801f7df9c..11a51f8ed3b 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -103,11 +103,11 @@ static void msix_set_enable(struct pci_dev *dev, int enable) } } -static void msix_flush_writes(unsigned int irq) +static void msix_flush_writes(struct irq_desc *desc) { struct msi_desc *entry; - entry = get_irq_msi(irq); + entry = get_irq_desc_msi(desc); BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: @@ -135,11 +135,11 @@ static void msix_flush_writes(unsigned int irq) * Returns 1 if it succeeded in masking the interrupt and 0 if the device * doesn't support MSI masking. */ -static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) +static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag) { struct msi_desc *entry; - entry = get_irq_msi(irq); + entry = get_irq_desc_msi(desc); BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: @@ -172,9 +172,9 @@ static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) return 1; } -void read_msi_msg(unsigned int irq, struct msi_msg *msg) +void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = get_irq_desc_msi(desc); switch(entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -211,9 +211,16 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) } } -void write_msi_msg(unsigned int irq, struct msi_msg *msg) +void read_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct irq_desc *desc = irq_to_desc(irq); + + read_msi_msg_desc(desc, msg); +} + +void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) +{ + struct msi_desc *entry = get_irq_desc_msi(desc); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -252,21 +259,31 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) entry->msg = *msg; } +void write_msi_msg(unsigned int irq, struct msi_msg *msg) +{ + struct irq_desc *desc = irq_to_desc(irq); + + write_msi_msg_desc(desc, msg); +} + void mask_msi_irq(unsigned int irq) { - msi_set_mask_bits(irq, 1, 1); - msix_flush_writes(irq); + struct irq_desc *desc = irq_to_desc(irq); + + msi_set_mask_bits(desc, 1, 1); + msix_flush_writes(desc); } void unmask_msi_irq(unsigned int irq) { - msi_set_mask_bits(irq, 1, 0); - msix_flush_writes(irq); + struct irq_desc *desc = irq_to_desc(irq); + + msi_set_mask_bits(desc, 1, 0); + msix_flush_writes(desc); } static int msi_free_irqs(struct pci_dev* dev); - static struct msi_desc* alloc_msi_entry(void) { struct msi_desc *entry; @@ -303,9 +320,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev) pci_intx_for_msi(dev, 0); msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); - if (entry->msi_attrib.maskbit) - msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask, + if (entry->msi_attrib.maskbit) { + struct irq_desc *desc = irq_to_desc(dev->irq); + msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask, entry->msi_attrib.masked); + } pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); control &= ~PCI_MSI_FLAGS_QSIZE; @@ -327,8 +346,9 @@ static void __pci_restore_msix_state(struct pci_dev *dev) msix_set_enable(dev, 0); list_for_each_entry(entry, &dev->msi_list, list) { + struct irq_desc *desc = irq_to_desc(entry->irq); write_msi_msg(entry->irq, &entry->msg); - msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked); + msi_set_mask_bits(desc, 1, entry->msi_attrib.masked); } BUG_ON(list_empty(&dev->msi_list)); @@ -596,7 +616,8 @@ void pci_msi_shutdown(struct pci_dev* dev) /* Return the the pci reset with msi irqs unmasked */ if (entry->msi_attrib.maskbit) { u32 mask = entry->msi_attrib.maskbits_mask; - msi_set_mask_bits(dev->irq, mask, ~mask); + struct irq_desc *desc = irq_to_desc(dev->irq); + msi_set_mask_bits(desc, mask, ~mask); } if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) return; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index b3a63edb690..ae5ec76dca7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -63,7 +63,7 @@ static acpi_status acpi_run_osc(acpi_handle handle, union acpi_object in_params[4]; struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *out_obj; - u32 osc_dw0, flags = osc_args->capbuf[OSC_QUERY_TYPE]; + u32 errors, flags = osc_args->capbuf[OSC_QUERY_TYPE]; /* Setting up input parameters */ input.count = 4; @@ -92,15 +92,16 @@ static acpi_status acpi_run_osc(acpi_handle handle, status = AE_TYPE; goto out_kfree; } - osc_dw0 = *((u32 *)out_obj->buffer.pointer); - if (osc_dw0) { - if (osc_dw0 & OSC_REQUEST_ERROR) + /* Need to ignore the bit0 in result code */ + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); + if (errors) { + if (errors & OSC_REQUEST_ERROR) printk(KERN_DEBUG "_OSC request fails\n"); - if (osc_dw0 & OSC_INVALID_UUID_ERROR) + if (errors & OSC_INVALID_UUID_ERROR) printk(KERN_DEBUG "_OSC invalid UUID\n"); - if (osc_dw0 & OSC_INVALID_REVISION_ERROR) + if (errors & OSC_INVALID_REVISION_ERROR) printk(KERN_DEBUG "_OSC invalid revision\n"); - if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { + if (errors & OSC_CAPABILITIES_MASK_ERROR) { if (flags & OSC_QUERY_ENABLE) goto out_success; printk(KERN_DEBUG "_OSC FW not grant req. control\n"); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 21f2ac639ca..061d1ee0046 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1832,7 +1832,7 @@ int pci_reset_function(struct pci_dev *dev) if (!(cap & PCI_EXP_DEVCAP_FLR)) return -ENOTTY; - if (!dev->msi_enabled && !dev->msix_enabled) + if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) disable_irq(dev->irq); pci_save_state(dev); @@ -1841,7 +1841,7 @@ int pci_reset_function(struct pci_dev *dev) r = pci_execute_reset_function(dev); pci_restore_state(dev); - if (!dev->msi_enabled && !dev->msix_enabled) + if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0) enable_irq(dev->irq); return r; @@ -2042,7 +2042,7 @@ static int __devinit pci_init(void) return 0; } -static int __devinit pci_setup(char *str) +static int __init pci_setup(char *str) { while (str) { char *k = strchr(str, ','); diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 8f63f4c6b85..9aad608bcf3 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -16,6 +16,7 @@ #include <linux/pm.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include <linux/pci-aspm.h> #include "../pci.h" @@ -161,11 +162,12 @@ static void pcie_check_clock_pm(struct pci_dev *pdev) */ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) { - int pos, child_pos; + int pos, child_pos, i = 0; u16 reg16 = 0; struct pci_dev *child_dev; int same_clock = 1; - + unsigned long start_jiffies; + u16 child_regs[8], parent_reg; /* * all functions of a slot should have the same Slot Clock * Configuration, so just check one function @@ -191,16 +193,19 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, ®16); + child_regs[i] = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else reg16 &= ~PCI_EXP_LNKCTL_CCC; pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, reg16); + i++; } /* Configure upstream component */ pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + parent_reg = reg16; if (same_clock) reg16 |= PCI_EXP_LNKCTL_CCC; else @@ -212,12 +217,30 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); /* Wait for link training end */ - while (1) { + /* break out after waiting for 1 second */ + start_jiffies = jiffies; + while ((jiffies - start_jiffies) < HZ) { pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); if (!(reg16 & PCI_EXP_LNKSTA_LT)) break; cpu_relax(); } + /* training failed -> recover */ + if ((jiffies - start_jiffies) >= HZ) { + dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure" + " common clock\n"); + i = 0; + list_for_each_entry(child_dev, &pdev->subordinate->devices, + bus_list) { + child_pos = pci_find_capability(child_dev, + PCI_CAP_ID_EXP); + pci_write_config_word(child_dev, + child_pos + PCI_EXP_LNKCTL, + child_regs[i]); + i++; + } + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, parent_reg); + } } /* diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 5049a47030a..5f4f85f56cb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/acpi.h> #include <linux/kallsyms.h> +#include <linux/dmi.h> #include "pci.h" int isa_dma_bridge_buggy; @@ -1828,6 +1829,22 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB, ht_enable_msi_mapping); +/* The P5N32-SLI Premium motherboard from Asus has a problem with msi + * for the MCP55 NIC. It is not yet determined whether the msi problem + * also affects other devices. As for now, turn off msi for this device. + */ +static void __devinit nvenet_msi_disable(struct pci_dev *dev) +{ + if (dmi_name_in_vendors("P5N32-SLI PREMIUM")) { + dev_info(&dev->dev, + "Disabling msi for MCP55 NIC on P5N32-SLI Premium\n"); + dev->no_msi = 1; + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, + PCI_DEVICE_ID_NVIDIA_NVENET_15, + nvenet_msi_disable); + static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) { struct pci_dev *host_bridge; diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 4dd1c3e157a..5a8ccb4f604 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -253,6 +253,7 @@ placeholder: __func__, pci_domain_nr(parent), parent->number, slot_nr); out: + kfree(slot_name); up_write(&pci_bus_sem); return slot; err: |