diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/Kconfig | 4 | ||||
-rw-r--r-- | drivers/pci/Makefile | 4 | ||||
-rw-r--r-- | drivers/pci/dmar.c | 12 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/rpaphp_core.c | 2 | ||||
-rw-r--r-- | drivers/pci/htirq.c | 16 | ||||
-rw-r--r-- | drivers/pci/intel-iommu.c | 97 | ||||
-rw-r--r-- | drivers/pci/intr_remapping.c | 4 | ||||
-rw-r--r-- | drivers/pci/iova.c | 2 | ||||
-rw-r--r-- | drivers/pci/msi.c | 10 | ||||
-rw-r--r-- | drivers/pci/pci-acpi.c | 16 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 6 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 4 | ||||
-rw-r--r-- | drivers/pci/pci.c | 6 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 9 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 182 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 33 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 5 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 4 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 4 |
21 files changed, 245 insertions, 179 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index c8ff646c0b0..0fa466a91bf 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -88,4 +88,6 @@ config PCI_IOAPIC depends on HOTPLUG default y -select NLS if (DMI || ACPI) +config PCI_LABEL + def_bool y if (DMI || ACPI) + select NLS diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98d61c8e984..c85f744270a 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,10 +56,10 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o # ACPI Related PCI FW Functions # ACPI _DSM provided firmware instance and string name # -obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o +obj-$(CONFIG_ACPI) += pci-acpi.o # SMBIOS provided firmware instance and labels -obj-$(CONFIG_DMI) += pci-label.o +obj-$(CONFIG_PCI_LABEL) += pci-label.o # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 09933eb9126..12e02bf92c4 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -1226,7 +1226,7 @@ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) void dmar_msi_unmask(struct irq_data *data) { - struct intel_iommu *iommu = irq_data_get_irq_data(data); + struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); unsigned long flag; /* unmask it */ @@ -1240,7 +1240,7 @@ void dmar_msi_unmask(struct irq_data *data) void dmar_msi_mask(struct irq_data *data) { unsigned long flag; - struct intel_iommu *iommu = irq_data_get_irq_data(data); + struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); /* mask it */ spin_lock_irqsave(&iommu->register_lock, flag); @@ -1252,7 +1252,7 @@ void dmar_msi_mask(struct irq_data *data) void dmar_msi_write(int irq, struct msi_msg *msg) { - struct intel_iommu *iommu = get_irq_data(irq); + struct intel_iommu *iommu = irq_get_handler_data(irq); unsigned long flag; spin_lock_irqsave(&iommu->register_lock, flag); @@ -1264,7 +1264,7 @@ void dmar_msi_write(int irq, struct msi_msg *msg) void dmar_msi_read(int irq, struct msi_msg *msg) { - struct intel_iommu *iommu = get_irq_data(irq); + struct intel_iommu *iommu = irq_get_handler_data(irq); unsigned long flag; spin_lock_irqsave(&iommu->register_lock, flag); @@ -1382,12 +1382,12 @@ int dmar_set_interrupt(struct intel_iommu *iommu) return -EINVAL; } - set_irq_data(irq, iommu); + irq_set_handler_data(irq, iommu); iommu->irq = irq; ret = arch_setup_dmar_msi(irq); if (ret) { - set_irq_data(irq, NULL); + irq_set_handler_data(irq, NULL); iommu->irq = 0; destroy_irq(irq); return ret; diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 3bc72d18b12..8f3faf343f7 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -351,7 +351,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) * To handle different BIOS behavior, we look for _OSC on a root * bridge preferentially (according to PCI fw spec). Later for * OSHP within the scope of the hotplug controller and its parents, - * upto the host bridge under which this controller exists. + * up to the host bridge under which this controller exists. */ handle = acpi_find_root_bridge_handle(pdev); if (handle) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e610cfe4f07..2f67e9bc2f9 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -585,7 +585,7 @@ static void remove_bridge(acpi_handle handle) /* * On root bridges with hotplug slots directly underneath (ie, - * no p2p bridge inbetween), we call cleanup_bridge(). + * no p2p bridge between), we call cleanup_bridge(). * * The else clause cleans up root bridges that either had no * hotplug slots at all, or had a p2p bridge underneath. diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index ef7411c660b..758adb5f47f 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -290,7 +290,7 @@ static int is_php_dn(struct device_node *dn, const int **indexes, * @dn: device node of slot * * This subroutine will register a hotplugable slot with the - * PCI hotplug infrastructure. This routine is typicaly called + * PCI hotplug infrastructure. This routine is typically called * during boot time, if the hotplug slots are present at boot time, * or is called later, by the dlpar add code, if the slot is * being dynamically added during runtime. diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 834842aa5bb..db057b6fe0c 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -34,7 +34,7 @@ struct ht_irq_cfg { void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { - struct ht_irq_cfg *cfg = get_irq_data(irq); + struct ht_irq_cfg *cfg = irq_get_handler_data(irq); unsigned long flags; spin_lock_irqsave(&ht_irq_lock, flags); if (cfg->msg.address_lo != msg->address_lo) { @@ -53,13 +53,13 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { - struct ht_irq_cfg *cfg = get_irq_data(irq); + struct ht_irq_cfg *cfg = irq_get_handler_data(irq); *msg = cfg->msg; } void mask_ht_irq(struct irq_data *data) { - struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); + struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); struct ht_irq_msg msg = cfg->msg; msg.address_lo |= 1; @@ -68,7 +68,7 @@ void mask_ht_irq(struct irq_data *data) void unmask_ht_irq(struct irq_data *data) { - struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); + struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); struct ht_irq_msg msg = cfg->msg; msg.address_lo &= ~1; @@ -126,7 +126,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) kfree(cfg); return -EBUSY; } - set_irq_data(irq, cfg); + irq_set_handler_data(irq, cfg); if (arch_setup_ht_irq(irq, dev) < 0) { ht_destroy_irq(irq); @@ -162,9 +162,9 @@ void ht_destroy_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - cfg = get_irq_data(irq); - set_irq_chip(irq, NULL); - set_irq_data(irq, NULL); + cfg = irq_get_handler_data(irq); + irq_set_chip(irq, NULL); + irq_set_handler_data(irq, NULL); destroy_irq(irq); kfree(cfg); diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4789f8e8bf7..d552d2c7784 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -36,7 +36,7 @@ #include <linux/iova.h> #include <linux/iommu.h> #include <linux/intel-iommu.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h> #include <linux/tboot.h> #include <linux/dmi.h> #include <asm/cacheflush.h> @@ -1206,7 +1206,7 @@ void free_dmar_iommu(struct intel_iommu *iommu) iommu_disable_translation(iommu); if (iommu->irq) { - set_irq_data(iommu->irq, NULL); + irq_set_handler_data(iommu->irq, NULL); /* This will mask the irq */ free_irq(iommu->irq, iommu); destroy_irq(iommu->irq); @@ -1299,7 +1299,7 @@ static void iommu_detach_domain(struct dmar_domain *domain, static struct iova_domain reserved_iova_list; static struct lock_class_key reserved_rbtree_key; -static void dmar_init_reserved_ranges(void) +static int dmar_init_reserved_ranges(void) { struct pci_dev *pdev = NULL; struct iova *iova; @@ -1313,8 +1313,10 @@ static void dmar_init_reserved_ranges(void) /* IOAPIC ranges shouldn't be accessed by DMA */ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), IOVA_PFN(IOAPIC_RANGE_END)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve IOAPIC range failed\n"); + return -ENODEV; + } /* Reserve all PCI MMIO to avoid peer-to-peer access */ for_each_pci_dev(pdev) { @@ -1327,11 +1329,13 @@ static void dmar_init_reserved_ranges(void) iova = reserve_iova(&reserved_iova_list, IOVA_PFN(r->start), IOVA_PFN(r->end)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve iova failed\n"); + return -ENODEV; + } } } - + return 0; } static void domain_reserve_special_ranges(struct dmar_domain *domain) @@ -1835,7 +1839,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) ret = iommu_attach_domain(domain, iommu); if (ret) { - domain_exit(domain); + free_domain_mem(domain); goto error; } @@ -2213,7 +2217,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw) return 0; } -int __init init_dmars(void) +static int __init init_dmars(int force_on) { struct dmar_drhd_unit *drhd; struct dmar_rmrr_unit *rmrr; @@ -2265,7 +2269,7 @@ int __init init_dmars(void) /* * TBD: * we could share the same root & context tables - * amoung all IOMMU's. Need to Split it later. + * among all IOMMU's. Need to Split it later. */ ret = iommu_alloc_root_entry(iommu); if (ret) { @@ -2393,8 +2397,15 @@ int __init init_dmars(void) * enable translation */ for_each_drhd_unit(drhd) { - if (drhd->ignored) + if (drhd->ignored) { + /* + * we always have to disable PMRs or DMA may fail on + * this device + */ + if (force_on) + iommu_disable_protect_mem_regions(drhd->iommu); continue; + } iommu = drhd->iommu; iommu_flush_write_buffer(iommu); @@ -3135,7 +3146,7 @@ static void iommu_flush_all(void) } } -static int iommu_suspend(struct sys_device *dev, pm_message_t state) +static int iommu_suspend(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu = NULL; @@ -3175,7 +3186,7 @@ nomem: return -ENOMEM; } -static int iommu_resume(struct sys_device *dev) +static void iommu_resume(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu = NULL; @@ -3183,7 +3194,7 @@ static int iommu_resume(struct sys_device *dev) if (init_iommu_hw()) { WARN(1, "IOMMU setup failed, DMAR can not resume!\n"); - return -EIO; + return; } for_each_active_iommu(iommu, drhd) { @@ -3204,40 +3215,20 @@ static int iommu_resume(struct sys_device *dev) for_each_active_iommu(iommu, drhd) kfree(iommu->iommu_state); - - return 0; } -static struct sysdev_class iommu_sysclass = { - .name = "iommu", +static struct syscore_ops iommu_syscore_ops = { .resume = iommu_resume, .suspend = iommu_suspend, }; -static struct sys_device device_iommu = { - .cls = &iommu_sysclass, -}; - -static int __init init_iommu_sysfs(void) +static void __init init_iommu_pm_ops(void) { - int error; - - error = sysdev_class_register(&iommu_sysclass); - if (error) - return error; - - error = sysdev_register(&device_iommu); - if (error) - sysdev_class_unregister(&iommu_sysclass); - - return error; + register_syscore_ops(&iommu_syscore_ops); } #else -static int __init init_iommu_sysfs(void) -{ - return 0; -} +static inline int init_iommu_pm_ops(void) { } #endif /* CONFIG_PM */ /* @@ -3260,9 +3251,15 @@ static int device_notifier(struct notifier_block *nb, if (!domain) return 0; - if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) + if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) { domain_remove_one_dev_info(domain, pdev); + if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) && + !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) && + list_empty(&domain->devices)) + domain_exit(domain); + } + return 0; } @@ -3297,12 +3294,21 @@ int __init intel_iommu_init(void) if (no_iommu || dmar_disabled) return -ENODEV; - iommu_init_mempool(); - dmar_init_reserved_ranges(); + if (iommu_init_mempool()) { + if (force_on) + panic("tboot: Failed to initialize iommu memory\n"); + return -ENODEV; + } + + if (dmar_init_reserved_ranges()) { + if (force_on) + panic("tboot: Failed to reserve iommu ranges\n"); + return -ENODEV; + } init_no_remapping_devices(); - ret = init_dmars(); + ret = init_dmars(force_on); if (ret) { if (force_on) panic("tboot: Failed to initialize DMARs\n"); @@ -3320,7 +3326,7 @@ int __init intel_iommu_init(void) #endif dma_ops = &intel_dma_ops; - init_iommu_sysfs(); + init_iommu_pm_ops(); register_iommu(&intel_iommu_ops); @@ -3411,6 +3417,11 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, domain->iommu_count--; domain_update_iommu_cap(domain); spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); + + spin_lock_irqsave(&iommu->lock, tmp_flags); + clear_bit(domain->id, iommu->domain_ids); + iommu->domains[domain->id] = NULL; + spin_unlock_irqrestore(&iommu->lock, tmp_flags); } spin_unlock_irqrestore(&device_domain_lock, flags); @@ -3627,9 +3638,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, pte = dmar_domain->pgd; if (dma_pte_present(pte)) { - free_pgtable_page(dmar_domain->pgd); dmar_domain->pgd = (struct dma_pte *) phys_to_virt(dma_pte_addr(pte)); + free_pgtable_page(pte); } dmar_domain->agaw--; } diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index ec87cd66f3e..3607faf28a4 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(irq_2_ir_lock); static struct irq_2_iommu *irq_2_iommu(unsigned int irq) { - struct irq_cfg *cfg = get_irq_chip_data(irq); + struct irq_cfg *cfg = irq_get_chip_data(irq); return cfg ? &cfg->irq_2_iommu : NULL; } @@ -289,7 +289,7 @@ int free_irte(int irq) * source validation type */ #define SVT_NO_VERIFY 0x0 /* no verification is required */ -#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fiels */ +#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fields */ #define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */ /* diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c index 7914951ef29..9606e599a47 100644 --- a/drivers/pci/iova.c +++ b/drivers/pci/iova.c @@ -391,7 +391,7 @@ reserve_iova(struct iova_domain *iovad, break; } - /* We are here either becasue this is the first reserver node + /* We are here either because this is the first reserver node * or need to insert remaining non overlap addr range */ iova = __insert_new_range(iovad, pfn_lo, pfn_hi); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 44b0aeee83e..2f10328bf66 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -236,7 +236,7 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void read_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); __read_msi_msg(entry, msg); } @@ -253,7 +253,7 @@ void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); __get_cached_msi_msg(entry, msg); } @@ -297,7 +297,7 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void write_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); __write_msi_msg(entry, msg); } @@ -354,7 +354,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) if (!dev->msi_enabled) return; - entry = get_irq_msi(dev->irq); + entry = irq_get_msi_desc(dev->irq); pos = entry->msi_attrib.pos; pci_intx_for_msi(dev, 0); @@ -519,7 +519,7 @@ static void msix_program_entries(struct pci_dev *dev, PCI_MSIX_ENTRY_VECTOR_CTRL; entries[i].vector = entry->irq; - set_irq_msi(entry->irq, entry); + irq_set_msi_desc(entry->irq, entry); entry->masked = readl(entry->mask_base + offset); msix_mask_irq(entry, 1); i++; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 6fe0772e0e7..7c3b18e78ce 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -293,19 +293,11 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable) } if (enable) { - if (!dev->wakeup.run_wake_count++) { - acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); - } - } else if (dev->wakeup.run_wake_count > 0) { - if (!--dev->wakeup.run_wake_count) { - acpi_disable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); - acpi_disable_wakeup_device_power(dev); - } + acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); + acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); } else { - error = -EALREADY; + acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); + acpi_disable_wakeup_device_power(dev); } return error; diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d86ea8b0113..135df164a4c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -781,7 +781,7 @@ static int pci_pm_resume(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int pci_pm_freeze(struct device *dev) { @@ -970,7 +970,7 @@ static int pci_pm_restore(struct device *dev) return error; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define pci_pm_freeze NULL #define pci_pm_freeze_noirq NULL @@ -981,7 +981,7 @@ static int pci_pm_restore(struct device *dev) #define pci_pm_restore NULL #define pci_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c85438a367d..f8deb3e380a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -369,7 +369,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ - if (security_capable(filp->f_cred, CAP_SYS_ADMIN) == 0) { + if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) { size = dev->cfg_size; } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { size = 128; @@ -645,7 +645,7 @@ pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) * a per-bus basis. This routine creates the files and ties them into * their associated read, write and mmap files from pci-sysfs.c * - * On error unwind, but don't propogate the error to the caller + * On error unwind, but don't propagate the error to the caller * as it is ok to set up the PCI bus without these files. */ void pci_create_legacy_files(struct pci_bus *b) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b714d787bdd..2472e7177b4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (!__pci_complete_power_transition(dev, state)) error = 0; + /* + * When aspm_policy is "powersave" this call ensures + * that ASPM is configured. + */ + if (!error && dev->bus->self) + pcie_aspm_powersave_config_link(dev->bus->self); return error; } diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 80c11d13149..3eb77080366 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -35,13 +35,6 @@ PCI_ERR_UNC_UNX_COMP| \ PCI_ERR_UNC_MALF_TLP) -struct header_log_regs { - unsigned int dw0; - unsigned int dw1; - unsigned int dw2; - unsigned int dw3; -}; - #define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ struct aer_err_info { struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; @@ -59,7 +52,7 @@ struct aer_err_info { unsigned int status; /* COR/UNCOR Error Status */ unsigned int mask; /* COR/UNCOR Error Mask */ - struct header_log_regs tlp; /* TLP Header */ + struct aer_header_log_regs tlp; /* TLP Header */ }; struct aer_err_source { diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 9d3e4c8d018..b07a42e0b35 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -19,6 +19,7 @@ #include <linux/errno.h> #include <linux/pm.h> #include <linux/suspend.h> +#include <linux/cper.h> #include "aerdrv.h" @@ -57,86 +58,44 @@ (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ AER_TRANSACTION_LAYER_ERROR) -#define AER_PR(info, pdev, fmt, args...) \ - printk("%s%s %s: " fmt, (info->severity == AER_CORRECTABLE) ? \ - KERN_WARNING : KERN_ERR, dev_driver_string(&pdev->dev), \ - dev_name(&pdev->dev), ## args) - /* * AER error strings */ -static char *aer_error_severity_string[] = { +static const char *aer_error_severity_string[] = { "Uncorrected (Non-Fatal)", "Uncorrected (Fatal)", "Corrected" }; -static char *aer_error_layer[] = { +static const char *aer_error_layer[] = { "Physical Layer", "Data Link Layer", "Transaction Layer" }; -static char *aer_correctable_error_string[] = { - "Receiver Error ", /* Bit Position 0 */ - NULL, - NULL, - NULL, - NULL, - NULL, - "Bad TLP ", /* Bit Position 6 */ - "Bad DLLP ", /* Bit Position 7 */ - "RELAY_NUM Rollover ", /* Bit Position 8 */ - NULL, - NULL, - NULL, - "Replay Timer Timeout ", /* Bit Position 12 */ - "Advisory Non-Fatal ", /* Bit Position 13 */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + +static const char *aer_correctable_error_string[] = { + "Receiver Error", /* Bit Position 0 */ NULL, NULL, NULL, NULL, NULL, + "Bad TLP", /* Bit Position 6 */ + "Bad DLLP", /* Bit Position 7 */ + "RELAY_NUM Rollover", /* Bit Position 8 */ NULL, NULL, NULL, + "Replay Timer Timeout", /* Bit Position 12 */ + "Advisory Non-Fatal", /* Bit Position 13 */ }; -static char *aer_uncorrectable_error_string[] = { - NULL, - NULL, - NULL, - NULL, - "Data Link Protocol ", /* Bit Position 4 */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "Poisoned TLP ", /* Bit Position 12 */ - "Flow Control Protocol ", /* Bit Position 13 */ - "Completion Timeout ", /* Bit Position 14 */ - "Completer Abort ", /* Bit Position 15 */ - "Unexpected Completion ", /* Bit Position 16 */ - "Receiver Overflow ", /* Bit Position 17 */ - "Malformed TLP ", /* Bit Position 18 */ - "ECRC ", /* Bit Position 19 */ - "Unsupported Request ", /* Bit Position 20 */ +static const char *aer_uncorrectable_error_string[] = { NULL, NULL, NULL, NULL, + "Data Link Protocol", /* Bit Position 4 */ NULL, NULL, NULL, @@ -144,19 +103,29 @@ static char *aer_uncorrectable_error_string[] = { NULL, NULL, NULL, + "Poisoned TLP", /* Bit Position 12 */ + "Flow Control Protocol", /* Bit Position 13 */ + "Completion Timeout", /* Bit Position 14 */ + "Completer Abort", /* Bit Position 15 */ + "Unexpected Completion", /* Bit Position 16 */ + "Receiver Overflow", /* Bit Position 17 */ + "Malformed TLP", /* Bit Position 18 */ + "ECRC", /* Bit Position 19 */ + "Unsupported Request", /* Bit Position 20 */ }; -static char *aer_agent_string[] = { +static const char *aer_agent_string[] = { "Receiver ID", "Requester ID", "Completer ID", "Transmitter ID" }; -static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) +static void __aer_print_error(const char *prefix, + struct aer_err_info *info) { int i, status; - char *errmsg = NULL; + const char *errmsg = NULL; status = (info->status & ~info->mask); @@ -165,15 +134,17 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) continue; if (info->severity == AER_CORRECTABLE) - errmsg = aer_correctable_error_string[i]; + errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? + aer_correctable_error_string[i] : NULL; else - errmsg = aer_uncorrectable_error_string[i]; + errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? + aer_uncorrectable_error_string[i] : NULL; if (errmsg) - AER_PR(info, dev, " [%2d] %s%s\n", i, errmsg, + printk("%s"" [%2d] %-22s%s\n", prefix, i, errmsg, info->first_error == i ? " (First)" : ""); else - AER_PR(info, dev, " [%2d] Unknown Error Bit%s\n", i, + printk("%s"" [%2d] Unknown Error Bit%s\n", prefix, i, info->first_error == i ? " (First)" : ""); } } @@ -181,11 +152,15 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { int id = ((dev->bus->number << 8) | dev->devfn); + char prefix[44]; + + snprintf(prefix, sizeof(prefix), "%s%s %s: ", + (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR, + dev_driver_string(&dev->dev), dev_name(&dev->dev)); if (info->status == 0) { - AER_PR(info, dev, - "PCIe Bus Error: severity=%s, type=Unaccessible, " - "id=%04x(Unregistered Agent ID)\n", + printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, " + "id=%04x(Unregistered Agent ID)\n", prefix, aer_error_severity_string[info->severity], id); } else { int layer, agent; @@ -193,23 +168,22 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) layer = AER_GET_LAYER_ERROR(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status); - AER_PR(info, dev, - "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", - aer_error_severity_string[info->severity], + printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", + prefix, aer_error_severity_string[info->severity], aer_error_layer[layer], id, aer_agent_string[agent]); - AER_PR(info, dev, - " device [%04x:%04x] error status/mask=%08x/%08x\n", - dev->vendor, dev->device, info->status, info->mask); + printk("%s"" device [%04x:%04x] error status/mask=%08x/%08x\n", + prefix, dev->vendor, dev->device, + info->status, info->mask); - __aer_print_error(info, dev); + __aer_print_error(prefix, info); if (info->tlp_header_valid) { unsigned char *tlp = (unsigned char *) &info->tlp; - AER_PR(info, dev, " TLP Header:" + printk("%s"" TLP Header:" " %02x%02x%02x%02x %02x%02x%02x%02x" " %02x%02x%02x%02x %02x%02x%02x%02x\n", - *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, + prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), *(tlp + 11), *(tlp + 10), *(tlp + 9), *(tlp + 8), *(tlp + 15), *(tlp + 14), @@ -218,8 +192,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) } if (info->id && info->error_dev_num > 1 && info->id == id) - AER_PR(info, dev, - " Error of this Agent(%04x) is reported first\n", id); + printk("%s"" Error of this Agent(%04x) is reported first\n", + prefix, id); } void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) @@ -228,3 +202,61 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) info->multi_error_valid ? "Multiple " : "", aer_error_severity_string[info->severity], info->id); } + +#ifdef CONFIG_ACPI_APEI_PCIEAER +static int cper_severity_to_aer(int cper_severity) +{ + switch (cper_severity) { + case CPER_SEV_RECOVERABLE: + return AER_NONFATAL; + case CPER_SEV_FATAL: + return AER_FATAL; + default: + return AER_CORRECTABLE; + } +} + +void cper_print_aer(const char *prefix, int cper_severity, + struct aer_capability_regs *aer) +{ + int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; + u32 status, mask; + const char **status_strs; + + aer_severity = cper_severity_to_aer(cper_severity); + if (aer_severity == AER_CORRECTABLE) { + status = aer->cor_status; + mask = aer->cor_mask; + status_strs = aer_correctable_error_string; + status_strs_size = ARRAY_SIZE(aer_correctable_error_string); + } else { + status = aer->uncor_status; + mask = aer->uncor_mask; + status_strs = aer_uncorrectable_error_string; + status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string); + tlp_header_valid = status & AER_LOG_TLP_MASKS; + } + layer = AER_GET_LAYER_ERROR(aer_severity, status); + agent = AER_GET_AGENT(aer_severity, status); + printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n", + prefix, status, mask); + cper_print_bits(prefix, status, status_strs, status_strs_size); + printk("%s""aer_layer=%s, aer_agent=%s\n", prefix, + aer_error_layer[layer], aer_agent_string[agent]); + if (aer_severity != AER_CORRECTABLE) + printk("%s""aer_uncor_severity: 0x%08x\n", + prefix, aer->uncor_severity); + if (tlp_header_valid) { + const unsigned char *tlp; + tlp = (const unsigned char *)&aer->header_log; + printk("%s""aer_tlp_header:" + " %02x%02x%02x%02x %02x%02x%02x%02x" + " %02x%02x%02x%02x %02x%02x%02x%02x\n", + prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, + *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), + *(tlp + 11), *(tlp + 10), *(tlp + 9), + *(tlp + 8), *(tlp + 15), *(tlp + 14), + *(tlp + 13), *(tlp + 12)); + } +} +#endif diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 3188cd96b33..eee09f756ec 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -69,6 +69,7 @@ struct pcie_link_state { }; static int aspm_disabled, aspm_force, aspm_clear_state; +static bool aspm_support_enabled = true; static DEFINE_MUTEX(aspm_lock); static LIST_HEAD(link_list); @@ -707,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) up_read(&pci_bus_sem); } +void pcie_aspm_powersave_config_link(struct pci_dev *pdev) +{ + struct pcie_link_state *link = pdev->link_state; + + if (aspm_disabled || !pci_is_pcie(pdev) || !link) + return; + + if (aspm_policy != POLICY_POWERSAVE) + return; + + if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && + (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + pcie_config_aspm_path(link); + pcie_set_clkpm(link, policy_to_clkpm_state(link)); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + /* * pci_disable_link_state - disable pci device's link state, so the link will * never enter specific states @@ -747,6 +770,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) int i; struct pcie_link_state *link; + if (aspm_disabled) + return -EPERM; for (i = 0; i < ARRAY_SIZE(policy_str); i++) if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) break; @@ -801,6 +826,8 @@ static ssize_t link_state_store(struct device *dev, struct pcie_link_state *link, *root = pdev->link_state->root; u32 val = buf[0] - '0', state = 0; + if (aspm_disabled) + return -EPERM; if (n < 1 || val > 3) return -EINVAL; @@ -896,6 +923,7 @@ static int __init pcie_aspm_disable(char *str) { if (!strcmp(str, "off")) { aspm_disabled = 1; + aspm_support_enabled = false; printk(KERN_INFO "PCIe ASPM is disabled\n"); } else if (!strcmp(str, "force")) { aspm_force = 1; @@ -930,3 +958,8 @@ int pcie_aspm_enabled(void) } EXPORT_SYMBOL(pcie_aspm_enabled); +bool pcie_aspm_support_enabled(void) +{ + return aspm_support_enabled; +} +EXPORT_SYMBOL(pcie_aspm_support_enabled); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 5130d0d2239..595654a1a6a 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -15,7 +15,6 @@ #include <linux/slab.h> #include <linux/pcieport_if.h> #include <linux/aer.h> -#include <linux/pci-aspm.h> #include "../pci.h" #include "portdrv.h" @@ -356,10 +355,8 @@ int pcie_port_device_register(struct pci_dev *dev) /* Get and check PCI Express port services */ capabilities = get_port_device_capability(dev); - if (!capabilities) { - pcie_no_aspm(); + if (!capabilities) return 0; - } pci_set_master(dev); /* diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bd80f637846..5129ed6d8fa 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -263,7 +263,7 @@ static void quirk_vialatency(struct pci_dev *dev) * This happens to include the IDE controllers.... * * VIA only apply this fix when an SB Live! is present but under - * both Linux and Windows this isnt enough, and we have seen + * both Linux and Windows this isn't enough, and we have seen * corruption without SB Live! but with things like 3 UDMA IDE * controllers. So we ignore that bit of the VIA recommendation.. */ @@ -2680,7 +2680,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0020, quirk_hotplug_bridge); * This is a quirk for the Ricoh MMC controller found as a part of * some mulifunction chips. - * This is very similiar and based on the ricoh_mmc driver written by + * This is very similar and based on the ricoh_mmc driver written by * Philip Langdale. Thank you for these magic sequences. * * These chips implement the four main memory card controllers (SD, MMC, MS, xD) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 89d0a6a88df..ebf51ad1b71 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -676,10 +676,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = align1 >> 1; align += aligns[order]; } - size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), align); + size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); size1 = !add_size ? size : calculate_memsize(size, min_size+add_size, 0, - resource_size(b_res), align); + resource_size(b_res), min_align); if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " |