| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $) |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
|---|
| 5 | 6 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 11 | | - * the Free Software Foundation; either version 2 of the License, or (at |
|---|
| 12 | | - * your option) any later version. |
|---|
| 13 | | - * |
|---|
| 14 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 15 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 17 | | - * General Public License for more details. |
|---|
| 18 | | - * |
|---|
| 19 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| 20 | 7 | */ |
|---|
| 21 | 8 | |
|---|
| 22 | 9 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 28 | 15 | #include <linux/pm_runtime.h> |
|---|
| 29 | 16 | #include <linux/pci.h> |
|---|
| 30 | 17 | #include <linux/pci-acpi.h> |
|---|
| 31 | | -#include <linux/pci-aspm.h> |
|---|
| 32 | 18 | #include <linux/dmar.h> |
|---|
| 33 | 19 | #include <linux/acpi.h> |
|---|
| 34 | 20 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 38 | 24 | |
|---|
| 39 | 25 | #include "internal.h" |
|---|
| 40 | 26 | |
|---|
| 41 | | -#define _COMPONENT ACPI_PCI_COMPONENT |
|---|
| 42 | | -ACPI_MODULE_NAME("pci_root"); |
|---|
| 43 | 27 | #define ACPI_PCI_ROOT_CLASS "pci_bridge" |
|---|
| 44 | 28 | #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" |
|---|
| 45 | 29 | static int acpi_pci_root_add(struct acpi_device *device, |
|---|
| .. | .. |
|---|
| 76 | 60 | |
|---|
| 77 | 61 | /** |
|---|
| 78 | 62 | * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge |
|---|
| 79 | | - * @handle - the ACPI CA node in question. |
|---|
| 63 | + * @handle: the ACPI CA node in question. |
|---|
| 80 | 64 | * |
|---|
| 81 | 65 | * Note: we could make this API take a struct acpi_device * instead, but |
|---|
| 82 | 66 | * for now, it's more convenient to operate on an acpi_handle. |
|---|
| .. | .. |
|---|
| 145 | 129 | { OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" }, |
|---|
| 146 | 130 | { OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" }, |
|---|
| 147 | 131 | { OSC_PCI_MSI_SUPPORT, "MSI" }, |
|---|
| 132 | + { OSC_PCI_EDR_SUPPORT, "EDR" }, |
|---|
| 133 | + { OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" }, |
|---|
| 148 | 134 | }; |
|---|
| 149 | 135 | |
|---|
| 150 | 136 | static struct pci_osc_bit_struct pci_osc_control_bit[] = { |
|---|
| .. | .. |
|---|
| 154 | 140 | { OSC_PCI_EXPRESS_AER_CONTROL, "AER" }, |
|---|
| 155 | 141 | { OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" }, |
|---|
| 156 | 142 | { OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" }, |
|---|
| 143 | + { OSC_PCI_EXPRESS_DPC_CONTROL, "DPC" }, |
|---|
| 157 | 144 | }; |
|---|
| 158 | 145 | |
|---|
| 159 | 146 | static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word, |
|---|
| .. | .. |
|---|
| 166 | 153 | buf[0] = '\0'; |
|---|
| 167 | 154 | for (i = 0, entry = table; i < size; i++, entry++) |
|---|
| 168 | 155 | if (word & entry->bit) |
|---|
| 169 | | - len += snprintf(buf + len, sizeof(buf) - len, "%s%s", |
|---|
| 156 | + len += scnprintf(buf + len, sizeof(buf) - len, "%s%s", |
|---|
| 170 | 157 | len ? " " : "", entry->desc); |
|---|
| 171 | 158 | |
|---|
| 172 | 159 | dev_info(&root->device->dev, "_OSC: %s [%s]\n", msg, buf); |
|---|
| .. | .. |
|---|
| 421 | 408 | } |
|---|
| 422 | 409 | EXPORT_SYMBOL(acpi_pci_osc_control_set); |
|---|
| 423 | 410 | |
|---|
| 424 | | -static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) |
|---|
| 411 | +static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, |
|---|
| 412 | + bool is_pcie) |
|---|
| 425 | 413 | { |
|---|
| 426 | 414 | u32 support, control, requested; |
|---|
| 427 | 415 | acpi_status status; |
|---|
| .. | .. |
|---|
| 445 | 433 | * PCI domains, so we indicate this in _OSC support capabilities. |
|---|
| 446 | 434 | */ |
|---|
| 447 | 435 | support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; |
|---|
| 436 | + support |= OSC_PCI_HPX_TYPE_3_SUPPORT; |
|---|
| 448 | 437 | if (pci_ext_cfg_avail()) |
|---|
| 449 | 438 | support |= OSC_PCI_EXT_CONFIG_SUPPORT; |
|---|
| 450 | 439 | if (pcie_aspm_support_enabled()) |
|---|
| 451 | 440 | support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT; |
|---|
| 452 | 441 | if (pci_msi_enabled()) |
|---|
| 453 | 442 | support |= OSC_PCI_MSI_SUPPORT; |
|---|
| 443 | + if (IS_ENABLED(CONFIG_PCIE_EDR)) |
|---|
| 444 | + support |= OSC_PCI_EDR_SUPPORT; |
|---|
| 454 | 445 | |
|---|
| 455 | 446 | decode_osc_support(root, "OS supports", support); |
|---|
| 456 | 447 | status = acpi_pci_osc_support(root, support); |
|---|
| 457 | 448 | if (ACPI_FAILURE(status)) { |
|---|
| 449 | + *no_aspm = 1; |
|---|
| 450 | + |
|---|
| 451 | + /* _OSC is optional for PCI host bridges */ |
|---|
| 452 | + if ((status == AE_NOT_FOUND) && !is_pcie) |
|---|
| 453 | + return; |
|---|
| 454 | + |
|---|
| 458 | 455 | dev_info(&device->dev, "_OSC failed (%s)%s\n", |
|---|
| 459 | 456 | acpi_format_exception(status), |
|---|
| 460 | 457 | pcie_aspm_support_enabled() ? "; disabling ASPM" : ""); |
|---|
| 461 | | - *no_aspm = 1; |
|---|
| 462 | 458 | return; |
|---|
| 463 | 459 | } |
|---|
| 464 | 460 | |
|---|
| .. | .. |
|---|
| 485 | 481 | if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) |
|---|
| 486 | 482 | control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; |
|---|
| 487 | 483 | |
|---|
| 488 | | - if (pci_aer_available()) { |
|---|
| 489 | | - if (aer_acpi_firmware_first()) |
|---|
| 490 | | - dev_info(&device->dev, |
|---|
| 491 | | - "PCIe AER handled by firmware\n"); |
|---|
| 492 | | - else |
|---|
| 493 | | - control |= OSC_PCI_EXPRESS_AER_CONTROL; |
|---|
| 494 | | - } |
|---|
| 484 | + if (pci_aer_available()) |
|---|
| 485 | + control |= OSC_PCI_EXPRESS_AER_CONTROL; |
|---|
| 486 | + |
|---|
| 487 | + /* |
|---|
| 488 | + * Per the Downstream Port Containment Related Enhancements ECN to |
|---|
| 489 | + * the PCI Firmware Spec, r3.2, sec 4.5.1, table 4-5, |
|---|
| 490 | + * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC |
|---|
| 491 | + * and EDR. |
|---|
| 492 | + */ |
|---|
| 493 | + if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR)) |
|---|
| 494 | + control |= OSC_PCI_EXPRESS_DPC_CONTROL; |
|---|
| 495 | 495 | |
|---|
| 496 | 496 | requested = control; |
|---|
| 497 | 497 | status = acpi_pci_osc_control_set(handle, &control, |
|---|
| .. | .. |
|---|
| 534 | 534 | acpi_handle handle = device->handle; |
|---|
| 535 | 535 | int no_aspm = 0; |
|---|
| 536 | 536 | bool hotadd = system_state == SYSTEM_RUNNING; |
|---|
| 537 | + bool is_pcie; |
|---|
| 537 | 538 | |
|---|
| 538 | 539 | root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); |
|---|
| 539 | 540 | if (!root) |
|---|
| .. | .. |
|---|
| 591 | 592 | |
|---|
| 592 | 593 | root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle); |
|---|
| 593 | 594 | |
|---|
| 594 | | - negotiate_os_control(root, &no_aspm); |
|---|
| 595 | + is_pcie = strcmp(acpi_device_hid(device), "PNP0A08") == 0; |
|---|
| 596 | + negotiate_os_control(root, &no_aspm, is_pcie); |
|---|
| 595 | 597 | |
|---|
| 596 | 598 | /* |
|---|
| 597 | 599 | * TBD: Need PCI interface for enumeration/configuration of roots. |
|---|
| .. | .. |
|---|
| 884 | 886 | int node = acpi_get_node(device->handle); |
|---|
| 885 | 887 | struct pci_bus *bus; |
|---|
| 886 | 888 | struct pci_host_bridge *host_bridge; |
|---|
| 889 | + union acpi_object *obj; |
|---|
| 887 | 890 | |
|---|
| 888 | 891 | info->root = root; |
|---|
| 889 | 892 | info->bridge = device; |
|---|
| .. | .. |
|---|
| 919 | 922 | host_bridge->native_pme = 0; |
|---|
| 920 | 923 | if (!(root->osc_control_set & OSC_PCI_EXPRESS_LTR_CONTROL)) |
|---|
| 921 | 924 | host_bridge->native_ltr = 0; |
|---|
| 925 | + if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL)) |
|---|
| 926 | + host_bridge->native_dpc = 0; |
|---|
| 927 | + |
|---|
| 928 | + /* |
|---|
| 929 | + * Evaluate the "PCI Boot Configuration" _DSM Function. If it |
|---|
| 930 | + * exists and returns 0, we must preserve any PCI resource |
|---|
| 931 | + * assignments made by firmware for this host bridge. |
|---|
| 932 | + */ |
|---|
| 933 | + obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, |
|---|
| 934 | + DSM_PCI_PRESERVE_BOOT_CONFIG, NULL); |
|---|
| 935 | + if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0) |
|---|
| 936 | + host_bridge->preserve_config = 1; |
|---|
| 937 | + ACPI_FREE(obj); |
|---|
| 922 | 938 | |
|---|
| 923 | 939 | pci_scan_child_bus(bus); |
|---|
| 924 | 940 | pci_set_host_bridge_release(host_bridge, acpi_pci_root_release_info, |
|---|