summaryrefslogtreecommitdiff
path: root/drivers/pci/pci-acpi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 23:03:49 +0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 23:03:49 +0400
commit80213c03c4151d900cf293ef0fc51f8d88495e14 (patch)
treeaf2422fa255aed96c23cef894e0adbf817f30c45 /drivers/pci/pci-acpi.c
parentea584595fc85e65796335033dfca25ed655cd0ed (diff)
parentf92d9ee3ab39841d1f29f2d1aa96ff7c74b36ee1 (diff)
downloadlinux-80213c03c4151d900cf293ef0fc51f8d88495e14.tar.xz
Merge tag 'pci-v3.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas: "The interesting things here are: - Turn on Config Request Retry Status Software Visibility. This caused hangs last time, but we included a fix this time. - Rework PCI device configuration to use _HPP/_HPX more aggressively - Allow PCI devices to be put into D3cold during system suspend - Add arm64 PCI support - Add APM X-Gene host bridge driver - Add TI Keystone host bridge driver - Add Xilinx AXI host bridge driver More detailed summary: Enumeration - Check Vendor ID only for Config Request Retry Status (Rajat Jain) - Enable Config Request Retry Status when supported (Rajat Jain) - Add generic domain handling (Catalin Marinas) - Generate uppercase hex for modalias interface class (Ricardo Ribalda Delgado) Resource management - Add missing MEM_64 mask in pci_assign_unassigned_bridge_resources() (Yinghai Lu) - Increase IBM ipr SAS Crocodile BARs to at least system page size (Douglas Lehr) PCI device hotplug - Prevent NULL dereference during pciehp probe (Andreas Noever) - Move _HPP & _HPX handling into core (Bjorn Helgaas) - Apply _HPP to PCIe devices as well as PCI (Bjorn Helgaas) - Apply _HPP/_HPX to display devices (Bjorn Helgaas) - Preserve SERR & PARITY settings when applying _HPP/_HPX (Bjorn Helgaas) - Preserve MPS and MRRS settings when applying _HPP/_HPX (Bjorn Helgaas) - Apply _HPP/_HPX to all devices, not just hot-added ones (Bjorn Helgaas) - Fix wait time in pciehp timeout message (Yinghai Lu) - Add more pciehp Slot Control debug output (Yinghai Lu) - Stop disabling pciehp notifications during init (Yinghai Lu) MSI - Remove arch_msi_check_device() (Alexander Gordeev) - Rename pci_msi_check_device() to pci_msi_supported() (Alexander Gordeev) - Move D0 check into pci_msi_check_device() (Alexander Gordeev) - Remove unused kobject from struct msi_desc (Yijing Wang) - Remove "pos" from the struct msi_desc msi_attrib (Yijing Wang) - Add "msi_bus" sysfs MSI/MSI-X control for endpoints (Yijing Wang) - Use __get_cached_msi_msg() instead of get_cached_msi_msg() (Yijing Wang) - Use __read_msi_msg() instead of read_msi_msg() (Yijing Wang) - Use __write_msi_msg() instead of write_msi_msg() (Yijing Wang) Power management - Drop unused runtime PM support code for PCIe ports (Rafael J. Wysocki) - Allow PCI devices to be put into D3cold during system suspend (Rafael J. Wysocki) AER - Add additional AER error strings (Gong Chen) - Make <linux/aer.h> standalone includable (Thierry Reding) Virtualization - Add ACS quirk for Solarflare SFC9120 & SFC9140 (Alex Williamson) - Add ACS quirk for Intel 10G NICs (Alex Williamson) - Add ACS quirk for AMD A88X southbridge (Marti Raudsepp) - Remove unused pci_find_upstream_pcie_bridge(), pci_get_dma_source() (Alex Williamson) - Add device flag helpers (Ethan Zhao) - Assume all Mellanox devices have broken INTx masking (Gavin Shan) Generic host bridge driver - Fix ioport_map() for !CONFIG_GENERIC_IOMAP (Liviu Dudau) - Add pci_register_io_range() and pci_pio_to_address() (Liviu Dudau) - Define PCI_IOBASE as the base of virtual PCI IO space (Liviu Dudau) - Fix the conversion of IO ranges into IO resources (Liviu Dudau) - Add pci_get_new_domain_nr() and of_get_pci_domain_nr() (Liviu Dudau) - Add support for parsing PCI host bridge resources from DT (Liviu Dudau) - Add pci_remap_iospace() to map bus I/O resources (Liviu Dudau) - Add arm64 architectural support for PCI (Liviu Dudau) APM X-Gene - Add APM X-Gene PCIe driver (Tanmay Inamdar) - Add arm64 DT APM X-Gene PCIe device tree nodes (Tanmay Inamdar) Freescale i.MX6 - Probe in module_init(), not fs_initcall() (Lucas Stach) - Delay enabling reference clock for SS until it stabilizes (Tim Harvey) Marvell MVEBU - Fix uninitialized variable in mvebu_get_tgt_attr() (Thomas Petazzoni) NVIDIA Tegra - Make sure the PCIe PLL is really reset (Eric Yuen) - Add error path tegra_msi_teardown_irq() cleanup (Jisheng Zhang) - Fix extended configuration space mapping (Peter Daifuku) - Implement resource hierarchy (Thierry Reding) - Clear CLKREQ# enable on port disable (Thierry Reding) - Add Tegra124 support (Thierry Reding) ST Microelectronics SPEAr13xx - Pass config resource through reg property (Pratyush Anand) Synopsys DesignWare - Use NULL instead of false (Fabio Estevam) - Parse bus-range property from devicetree (Lucas Stach) - Use pci_create_root_bus() instead of pci_scan_root_bus() (Lucas Stach) - Remove pci_assign_unassigned_resources() (Lucas Stach) - Check private_data validity in single place (Lucas Stach) - Setup and clear exactly one MSI at a time (Lucas Stach) - Remove open-coded bitmap operations (Lucas Stach) - Fix configuration base address when using 'reg' (Minghuan Lian) - Fix IO resource end address calculation (Minghuan Lian) - Rename get_msi_data() to get_msi_addr() (Minghuan Lian) - Add get_msi_data() to pcie_host_ops (Minghuan Lian) - Add support for v3.65 hardware (Murali Karicheri) - Fold struct pcie_port_info into struct pcie_port (Pratyush Anand) TI Keystone - Add TI Keystone PCIe driver (Murali Karicheri) - Limit MRSS for all downstream devices (Murali Karicheri) - Assume controller is already in RC mode (Murali Karicheri) - Set device ID based on SoC to support multiple ports (Murali Karicheri) Xilinx AXI - Add Xilinx AXI PCIe driver (Srikanth Thokala) - Fix xilinx_pcie_assign_msi() return value test (Dan Carpenter) Miscellaneous - Clean up whitespace (Quentin Lambert) - Remove assignments from "if" conditions (Quentin Lambert) - Move PCI_VENDOR_ID_VMWARE to pci_ids.h (Francesco Ruggeri) - x86: Mark DMI tables as initialization data (Mathias Krause) - x86: Move __init annotation to the correct place (Mathias Krause) - x86: Mark constants of pci_mmcfg_nvidia_mcp55() as __initconst (Mathias Krause) - x86: Constify pci_mmcfg_probes[] array (Mathias Krause) - x86: Mark PCI BIOS initialization code as such (Mathias Krause) - Parenthesize PCI_DEVID and PCI_VPD_LRDT_ID parameters (Megan Kamiya) - Remove unnecessary variable in pci_add_dynid() (Tobias Klauser)" * tag 'pci-v3.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (109 commits) arm64: dts: Add APM X-Gene PCIe device tree nodes PCI: Add ACS quirk for AMD A88X southbridge devices PCI: xgene: Add APM X-Gene PCIe driver PCI: designware: Remove open-coded bitmap operations PCI/MSI: Remove unnecessary temporary variable PCI/MSI: Use __write_msi_msg() instead of write_msi_msg() MSI/powerpc: Use __read_msi_msg() instead of read_msi_msg() PCI/MSI: Use __get_cached_msi_msg() instead of get_cached_msi_msg() PCI/MSI: Add "msi_bus" sysfs MSI/MSI-X control for endpoints PCI/MSI: Remove "pos" from the struct msi_desc msi_attrib PCI/MSI: Remove unused kobject from struct msi_desc PCI/MSI: Rename pci_msi_check_device() to pci_msi_supported() PCI/MSI: Move D0 check into pci_msi_check_device() PCI/MSI: Remove arch_msi_check_device() irqchip: armada-370-xp: Remove arch_msi_check_device() PCI/MSI/PPC: Remove arch_msi_check_device() arm64: Add architectural support for PCI PCI: Add pci_remap_iospace() to map bus I/O resources of/pci: Add support for parsing PCI host bridge resources from DT of/pci: Add pci_get_new_domain_nr() and of_get_pci_domain_nr() ... Conflicts: arch/arm64/boot/dts/apm-storm.dtsi
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r--drivers/pci/pci-acpi.c276
1 files changed, 262 insertions, 14 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 37263b0ebfe3..6ebf8edc5f3c 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/module.h>
#include <linux/pci-aspm.h>
#include <linux/pci-acpi.h>
@@ -17,6 +18,267 @@
#include <linux/pm_qos.h>
#include "pci.h"
+phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
+{
+ acpi_status status = AE_NOT_EXIST;
+ unsigned long long mcfg_addr;
+
+ if (handle)
+ status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
+ NULL, &mcfg_addr);
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ return (phys_addr_t)mcfg_addr;
+}
+
+static acpi_status decode_type0_hpx_record(union acpi_object *record,
+ struct hotplug_params *hpx)
+{
+ int i;
+ union acpi_object *fields = record->package.elements;
+ u32 revision = fields[1].integer.value;
+
+ switch (revision) {
+ case 1:
+ if (record->package.count != 6)
+ return AE_ERROR;
+ for (i = 2; i < 6; i++)
+ if (fields[i].type != ACPI_TYPE_INTEGER)
+ return AE_ERROR;
+ hpx->t0 = &hpx->type0_data;
+ hpx->t0->revision = revision;
+ hpx->t0->cache_line_size = fields[2].integer.value;
+ hpx->t0->latency_timer = fields[3].integer.value;
+ hpx->t0->enable_serr = fields[4].integer.value;
+ hpx->t0->enable_perr = fields[5].integer.value;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Type 0 Revision %d record not supported\n",
+ __func__, revision);
+ return AE_ERROR;
+ }
+ return AE_OK;
+}
+
+static acpi_status decode_type1_hpx_record(union acpi_object *record,
+ struct hotplug_params *hpx)
+{
+ int i;
+ union acpi_object *fields = record->package.elements;
+ u32 revision = fields[1].integer.value;
+
+ switch (revision) {
+ case 1:
+ if (record->package.count != 5)
+ return AE_ERROR;
+ for (i = 2; i < 5; i++)
+ if (fields[i].type != ACPI_TYPE_INTEGER)
+ return AE_ERROR;
+ hpx->t1 = &hpx->type1_data;
+ hpx->t1->revision = revision;
+ hpx->t1->max_mem_read = fields[2].integer.value;
+ hpx->t1->avg_max_split = fields[3].integer.value;
+ hpx->t1->tot_max_split = fields[4].integer.value;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Type 1 Revision %d record not supported\n",
+ __func__, revision);
+ return AE_ERROR;
+ }
+ return AE_OK;
+}
+
+static acpi_status decode_type2_hpx_record(union acpi_object *record,
+ struct hotplug_params *hpx)
+{
+ int i;
+ union acpi_object *fields = record->package.elements;
+ u32 revision = fields[1].integer.value;
+
+ switch (revision) {
+ case 1:
+ if (record->package.count != 18)
+ return AE_ERROR;
+ for (i = 2; i < 18; i++)
+ if (fields[i].type != ACPI_TYPE_INTEGER)
+ return AE_ERROR;
+ hpx->t2 = &hpx->type2_data;
+ hpx->t2->revision = revision;
+ hpx->t2->unc_err_mask_and = fields[2].integer.value;
+ hpx->t2->unc_err_mask_or = fields[3].integer.value;
+ hpx->t2->unc_err_sever_and = fields[4].integer.value;
+ hpx->t2->unc_err_sever_or = fields[5].integer.value;
+ hpx->t2->cor_err_mask_and = fields[6].integer.value;
+ hpx->t2->cor_err_mask_or = fields[7].integer.value;
+ hpx->t2->adv_err_cap_and = fields[8].integer.value;
+ hpx->t2->adv_err_cap_or = fields[9].integer.value;
+ hpx->t2->pci_exp_devctl_and = fields[10].integer.value;
+ hpx->t2->pci_exp_devctl_or = fields[11].integer.value;
+ hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value;
+ hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value;
+ hpx->t2->sec_unc_err_sever_and = fields[14].integer.value;
+ hpx->t2->sec_unc_err_sever_or = fields[15].integer.value;
+ hpx->t2->sec_unc_err_mask_and = fields[16].integer.value;
+ hpx->t2->sec_unc_err_mask_or = fields[17].integer.value;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Type 2 Revision %d record not supported\n",
+ __func__, revision);
+ return AE_ERROR;
+ }
+ return AE_OK;
+}
+
+static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *package, *record, *fields;
+ u32 type;
+ int i;
+
+ /* Clear the return buffer with zeros */
+ memset(hpx, 0, sizeof(struct hotplug_params));
+
+ status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ package = (union acpi_object *)buffer.pointer;
+ if (package->type != ACPI_TYPE_PACKAGE) {
+ status = AE_ERROR;
+ goto exit;
+ }
+
+ for (i = 0; i < package->package.count; i++) {
+ record = &package->package.elements[i];
+ if (record->type != ACPI_TYPE_PACKAGE) {
+ status = AE_ERROR;
+ goto exit;
+ }
+
+ fields = record->package.elements;
+ if (fields[0].type != ACPI_TYPE_INTEGER ||
+ fields[1].type != ACPI_TYPE_INTEGER) {
+ status = AE_ERROR;
+ goto exit;
+ }
+
+ type = fields[0].integer.value;
+ switch (type) {
+ case 0:
+ status = decode_type0_hpx_record(record, hpx);
+ if (ACPI_FAILURE(status))
+ goto exit;
+ break;
+ case 1:
+ status = decode_type1_hpx_record(record, hpx);
+ if (ACPI_FAILURE(status))
+ goto exit;
+ break;
+ case 2:
+ status = decode_type2_hpx_record(record, hpx);
+ if (ACPI_FAILURE(status))
+ goto exit;
+ break;
+ default:
+ printk(KERN_ERR "%s: Type %d record not supported\n",
+ __func__, type);
+ status = AE_ERROR;
+ goto exit;
+ }
+ }
+ exit:
+ kfree(buffer.pointer);
+ return status;
+}
+
+static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *package, *fields;
+ int i;
+
+ memset(hpp, 0, sizeof(struct hotplug_params));
+
+ status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ package = (union acpi_object *) buffer.pointer;
+ if (package->type != ACPI_TYPE_PACKAGE ||
+ package->package.count != 4) {
+ status = AE_ERROR;
+ goto exit;
+ }
+
+ fields = package->package.elements;
+ for (i = 0; i < 4; i++) {
+ if (fields[i].type != ACPI_TYPE_INTEGER) {
+ status = AE_ERROR;
+ goto exit;
+ }
+ }
+
+ hpp->t0 = &hpp->type0_data;
+ hpp->t0->revision = 1;
+ hpp->t0->cache_line_size = fields[0].integer.value;
+ hpp->t0->latency_timer = fields[1].integer.value;
+ hpp->t0->enable_serr = fields[2].integer.value;
+ hpp->t0->enable_perr = fields[3].integer.value;
+
+exit:
+ kfree(buffer.pointer);
+ return status;
+}
+
+/* pci_get_hp_params
+ *
+ * @dev - the pci_dev for which we want parameters
+ * @hpp - allocated by the caller
+ */
+int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
+{
+ acpi_status status;
+ acpi_handle handle, phandle;
+ struct pci_bus *pbus;
+
+ handle = NULL;
+ for (pbus = dev->bus; pbus; pbus = pbus->parent) {
+ handle = acpi_pci_get_bridge_handle(pbus);
+ if (handle)
+ break;
+ }
+
+ /*
+ * _HPP settings apply to all child buses, until another _HPP is
+ * encountered. If we don't find an _HPP for the input pci dev,
+ * look for it in the parent device scope since that would apply to
+ * this pci dev.
+ */
+ while (handle) {
+ status = acpi_run_hpx(handle, hpp);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ status = acpi_run_hpp(handle, hpp);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ if (acpi_is_root_bridge(handle))
+ break;
+ status = acpi_get_parent(handle, &phandle);
+ if (ACPI_FAILURE(status))
+ break;
+ handle = phandle;
+ }
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(pci_get_hp_params);
+
/**
* pci_acpi_wake_bus - Root bus wakeup notification fork function.
* @work: Work item to handle.
@@ -84,20 +346,6 @@ acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
}
-phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
-{
- acpi_status status = AE_NOT_EXIST;
- unsigned long long mcfg_addr;
-
- if (handle)
- status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
- NULL, &mcfg_addr);
- if (ACPI_FAILURE(status))
- return 0;
-
- return (phys_addr_t)mcfg_addr;
-}
-
/*
* _SxD returns the D-state with the highest power
* (lowest D-state number) supported in the S-state "x".