.. | .. |
---|
| 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, |
---|