summaryrefslogtreecommitdiff
path: root/drivers/pci/pcie
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r--drivers/pci/pcie/Kconfig3
-rw-r--r--drivers/pci/pcie/aer/Kconfig1
-rw-r--r--drivers/pci/pcie/aer/Kconfig.debug1
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c22
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c7
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c31
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c27
-rw-r--r--drivers/pci/pcie/aer/ecrc.c16
-rw-r--r--drivers/pci/pcie/aspm.c80
-rw-r--r--drivers/pci/pcie/pcie-dpc.c256
-rw-r--r--drivers/pci/pcie/pme.c11
-rw-r--r--drivers/pci/pcie/portdrv_acpi.c5
-rw-r--r--drivers/pci/pcie/portdrv_bus.c1
-rw-r--r--drivers/pci/pcie/portdrv_core.c4
-rw-r--r--drivers/pci/pcie/ptm.c12
15 files changed, 207 insertions, 270 deletions
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index ac53edbc9613..b12e28b3d8f9 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# PCI Express Port Bus Configuration
#
@@ -92,7 +93,7 @@ config PCIE_PME
config PCIE_DPC
bool "PCIe Downstream Port Containment support"
- depends on PCIEPORTBUS
+ depends on PCIEPORTBUS && PCIEAER
default n
help
This enables PCI Express Downstream Port Containment (DPC)
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
index 7d1437b01fdd..5a64eb3d6c7a 100644
--- a/drivers/pci/pcie/aer/Kconfig
+++ b/drivers/pci/pcie/aer/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# PCI Express Root Port Device AER Configuration
#
diff --git a/drivers/pci/pcie/aer/Kconfig.debug b/drivers/pci/pcie/aer/Kconfig.debug
index 9142949734f5..67e02174b65b 100644
--- a/drivers/pci/pcie/aer/Kconfig.debug
+++ b/drivers/pci/pcie/aer/Kconfig.debug
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
#
# PCI Express Root Port Device AER Debug Configuration
#
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 2b6a59266689..25e1feb962c5 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCIe AER software error injection support.
*
@@ -9,12 +10,6 @@
*
* Copyright 2009 Intel Corporation.
* Huang Ying <ying.huang@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- *
*/
#include <linux/module.h>
@@ -344,14 +339,14 @@ static int aer_inject(struct aer_error_inj *einj)
return -ENODEV;
rpdev = pcie_find_root_port(dev);
if (!rpdev) {
- dev_err(&dev->dev, "aer_inject: Root port not found\n");
+ pci_err(dev, "aer_inject: Root port not found\n");
ret = -ENODEV;
goto out_put;
}
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos_cap_err) {
- dev_err(&dev->dev, "aer_inject: Device doesn't support AER\n");
+ pci_err(dev, "aer_inject: Device doesn't support AER\n");
ret = -EPROTONOSUPPORT;
goto out_put;
}
@@ -362,8 +357,7 @@ static int aer_inject(struct aer_error_inj *einj)
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
if (!rp_pos_cap_err) {
- dev_err(&rpdev->dev,
- "aer_inject: Root port doesn't support AER\n");
+ pci_err(rpdev, "aer_inject: Root port doesn't support AER\n");
ret = -EPROTONOSUPPORT;
goto out_put;
}
@@ -411,16 +405,14 @@ static int aer_inject(struct aer_error_inj *einj)
if (!aer_mask_override && einj->cor_status &&
!(einj->cor_status & ~cor_mask)) {
ret = -EINVAL;
- dev_warn(&dev->dev,
- "aer_inject: The correctable error(s) is masked by device\n");
+ pci_warn(dev, "aer_inject: The correctable error(s) is masked by device\n");
spin_unlock_irqrestore(&inject_lock, flags);
goto out_put;
}
if (!aer_mask_override && einj->uncor_status &&
!(einj->uncor_status & ~uncor_mask)) {
ret = -EINVAL;
- dev_warn(&dev->dev,
- "aer_inject: The uncorrectable error(s) is masked by device\n");
+ pci_warn(dev, "aer_inject: The uncorrectable error(s) is masked by device\n");
spin_unlock_irqrestore(&inject_lock, flags);
goto out_put;
}
@@ -483,7 +475,7 @@ static int aer_inject(struct aer_error_inj *einj)
einj->cor_status, einj->uncor_status, pci_name(dev));
aer_irq(-1, edev);
} else {
- dev_err(&rpdev->dev, "aer_inject: AER device not found\n");
+ pci_err(rpdev, "aer_inject: AER device not found\n");
ret = -ENODEV;
}
out_put:
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 6ff5f5b4f5e6..da8331f5684d 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* drivers/pci/pcie/aer/aerdrv.c
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
* This file implements the AER root port service driver. The driver will
* register an irq handler. When root port triggers an AER interrupt, the irq
* handler will collect root port status and schedule a work.
@@ -326,7 +323,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
pci_reset_bridge_secondary_bus(dev);
- dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
+ pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n");
/* Clear Root Error Status */
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 8d7448063fd1..a4bfea52e7d4 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* drivers/pci/pcie/aer/aerdrv_core.c
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
* This file implements the core part of PCIe AER. When a PCIe
* error is delivered, an error message will be collected and printed to
* console, then, an error recovery procedure will be executed by following
@@ -226,9 +223,8 @@ static bool find_source_device(struct pci_dev *parent,
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
if (!e_info->error_dev_num) {
- dev_printk(KERN_DEBUG, &parent->dev,
- "can't find device of ID%04x\n",
- e_info->id);
+ pci_printk(KERN_DEBUG, parent, "can't find device of ID%04x\n",
+ e_info->id);
return false;
}
return true;
@@ -256,7 +252,7 @@ static int report_error_detected(struct pci_dev *dev, void *data)
* of a driver for this device is unaware of
* its hw state.
*/
- dev_printk(KERN_DEBUG, &dev->dev, "device has %s\n",
+ pci_printk(KERN_DEBUG, dev, "device has %s\n",
dev->driver ?
"no AER-aware driver" : "no driver");
}
@@ -366,7 +362,7 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
{
struct aer_broadcast_data result_data;
- dev_printk(KERN_DEBUG, &dev->dev, "broadcast %s message\n", error_mesg);
+ pci_printk(KERN_DEBUG, dev, "broadcast %s message\n", error_mesg);
result_data.state = state;
if (cb == report_error_detected)
result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
@@ -415,7 +411,7 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
static pci_ers_result_t default_reset_link(struct pci_dev *dev)
{
pci_reset_bridge_secondary_bus(dev);
- dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n");
+ pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
return PCI_ERS_RESULT_RECOVERED;
}
@@ -467,15 +463,13 @@ static pci_ers_result_t reset_link(struct pci_dev *dev)
} else if (udev->has_secondary_link) {
status = default_reset_link(udev);
} else {
- dev_printk(KERN_DEBUG, &dev->dev,
- "no link-reset support at upstream device %s\n",
+ pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
pci_name(udev));
return PCI_ERS_RESULT_DISCONNECT;
}
if (status != PCI_ERS_RESULT_RECOVERED) {
- dev_printk(KERN_DEBUG, &dev->dev,
- "link reset at upstream device %s failed\n",
+ pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n",
pci_name(udev));
return PCI_ERS_RESULT_DISCONNECT;
}
@@ -539,13 +533,13 @@ static void do_recovery(struct pci_dev *dev, int severity)
"resume",
report_resume);
- dev_info(&dev->dev, "AER: Device recovery successful\n");
+ pci_info(dev, "AER: Device recovery successful\n");
return;
failed:
pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
/* TODO: Should kernel panic here? */
- dev_info(&dev->dev, "AER: Device recovery failed\n");
+ pci_info(dev, "AER: Device recovery failed\n");
}
/**
@@ -636,7 +630,8 @@ static void aer_recover_work_func(struct work_struct *work)
continue;
}
cper_print_aer(pdev, entry.severity, entry.regs);
- do_recovery(pdev, entry.severity);
+ if (entry.severity != AER_CORRECTABLE)
+ do_recovery(pdev, entry.severity);
pci_dev_put(pdev);
}
}
@@ -663,7 +658,7 @@ static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
/* The device might not support AER */
if (!pos)
- return 1;
+ return 0;
if (info->severity == AER_CORRECTABLE) {
pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
index 54c4b691e51f..6a352e638699 100644
--- a/drivers/pci/pcie/aer/aerdrv_errprint.c
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* drivers/pci/pcie/aer/aerdrv_errprint.c
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
* Format error messages and print them to console.
*
* Copyright (C) 2006 Intel Corp.
@@ -132,7 +129,7 @@ static const char *aer_agent_string[] = {
static void __print_tlp_header(struct pci_dev *dev,
struct aer_header_log_regs *t)
{
- dev_err(&dev->dev, " TLP Header: %08x %08x %08x %08x\n",
+ pci_err(dev, " TLP Header: %08x %08x %08x %08x\n",
t->dw0, t->dw1, t->dw2, t->dw3);
}
@@ -155,10 +152,10 @@ static void __aer_print_error(struct pci_dev *dev,
aer_uncorrectable_error_string[i] : NULL;
if (errmsg)
- dev_err(&dev->dev, " [%2d] %-22s%s\n", i, errmsg,
+ pci_err(dev, " [%2d] %-22s%s\n", i, errmsg,
info->first_error == i ? " (First)" : "");
else
- dev_err(&dev->dev, " [%2d] Unknown Error Bit%s\n",
+ pci_err(dev, " [%2d] Unknown Error Bit%s\n",
i, info->first_error == i ? " (First)" : "");
}
}
@@ -169,7 +166,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
int id = ((dev->bus->number << 8) | dev->devfn);
if (!info->status) {
- dev_err(&dev->dev, "PCIe Bus Error: severity=%s, type=Unaccessible, id=%04x(Unregistered Agent ID)\n",
+ pci_err(dev, "PCIe Bus Error: severity=%s, type=Unaccessible, id=%04x(Unregistered Agent ID)\n",
aer_error_severity_string[info->severity], id);
goto out;
}
@@ -177,11 +174,11 @@ 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);
- dev_err(&dev->dev, "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
+ pci_err(dev, "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
aer_error_severity_string[info->severity],
aer_error_layer[layer], id, aer_agent_string[agent]);
- dev_err(&dev->dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
+ pci_err(dev, " device [%04x:%04x] error status/mask=%08x/%08x\n",
dev->vendor, dev->device,
info->status, info->mask);
@@ -192,7 +189,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
out:
if (info->id && info->error_dev_num > 1 && info->id == id)
- dev_err(&dev->dev, " Error of this Agent(%04x) is reported first\n", id);
+ pci_err(dev, " Error of this Agent(%04x) is reported first\n", id);
trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
info->severity);
@@ -200,7 +197,7 @@ out:
void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
{
- dev_info(&dev->dev, "AER: %s%s error received: id=%04x\n",
+ pci_info(dev, "AER: %s%s error received: id=%04x\n",
info->multi_error_valid ? "Multiple " : "",
aer_error_severity_string[info->severity], info->id);
}
@@ -242,13 +239,13 @@ void cper_print_aer(struct pci_dev *dev, int aer_severity,
layer = AER_GET_LAYER_ERROR(aer_severity, status);
agent = AER_GET_AGENT(aer_severity, status);
- dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
+ pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
cper_print_bits("", status, status_strs, status_strs_size);
- dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n",
+ pci_err(dev, "aer_layer=%s, aer_agent=%s\n",
aer_error_layer[layer], aer_agent_string[agent]);
if (aer_severity != AER_CORRECTABLE)
- dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n",
+ pci_err(dev, "aer_uncor_severity: 0x%08x\n",
aer->uncor_severity);
if (tlp_header_valid)
diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c
index a2747a663bc9..26d3cac9e635 100644
--- a/drivers/pci/pcie/aer/ecrc.c
+++ b/drivers/pci/pcie/aer/ecrc.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Enables/disables PCIe ECRC checking.
*
* (C) Copyright 2009 Hewlett-Packard Development Company, L.P.
* Andrew Patterson <andrew.patterson@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307, USA.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 9783e10da3a9..57feef2ecfe7 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -43,18 +43,6 @@
#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \
ASPM_STATE_L1SS)
-/*
- * When L1 substates are enabled, the LTR L1.2 threshold is a timing parameter
- * that decides whether L1.1 or L1.2 is entered (Refer PCIe spec for details).
- * Not sure is there is a way to "calculate" this on the fly, but maybe we
- * could turn it into a parameter in future. This value has been taken from
- * the following files from Intel's coreboot (which is the only code I found
- * to have used this):
- * https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html
- * https://review.coreboot.org/#/c/8832/
- */
-#define LTR_L1_2_THRESHOLD_BITS ((1 << 21) | (1 << 23) | (1 << 30))
-
struct aspm_latency {
u32 l0s; /* L0s latency (nsec) */
u32 l1; /* L1 latency (nsec) */
@@ -278,7 +266,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
return;
/* Training failed. Restore common clock configurations */
- dev_err(&parent->dev, "ASPM: Could not configure common clock\n");
+ pci_err(parent, "ASPM: Could not configure common clock\n");
list_for_each_entry(child, &linkbus->devices, bus_list)
pcie_capability_write_word(child, PCI_EXP_LNKCTL,
child_reg[PCI_FUNC(child->devfn)]);
@@ -328,11 +316,36 @@ static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
case 2:
return val * 100;
}
- dev_err(&pdev->dev, "%s: Invalid T_PwrOn scale: %u\n",
- __func__, scale);
+ pci_err(pdev, "%s: Invalid T_PwrOn scale: %u\n", __func__, scale);
return 0;
}
+static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
+{
+ u64 threshold_ns = threshold_us * 1000;
+
+ /* See PCIe r3.1, sec 7.33.3 and sec 6.18 */
+ if (threshold_ns < 32) {
+ *scale = 0;
+ *value = threshold_ns;
+ } else if (threshold_ns < 1024) {
+ *scale = 1;
+ *value = threshold_ns >> 5;
+ } else if (threshold_ns < 32768) {
+ *scale = 2;
+ *value = threshold_ns >> 10;
+ } else if (threshold_ns < 1048576) {
+ *scale = 3;
+ *value = threshold_ns >> 15;
+ } else if (threshold_ns < 33554432) {
+ *scale = 4;
+ *value = threshold_ns >> 20;
+ } else {
+ *scale = 5;
+ *value = threshold_ns >> 25;
+ }
+}
+
struct aspm_register_info {
u32 support:2;
u32 enabled:2;
@@ -443,6 +456,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
struct aspm_register_info *dwreg)
{
u32 val1, val2, scale1, scale2;
+ u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
@@ -454,16 +468,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
/* Choose the greater of the two Port Common_Mode_Restore_Times */
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
val2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
- if (val1 > val2)
- link->l1ss.ctl1 |= val1 << 8;
- else
- link->l1ss.ctl1 |= val2 << 8;
-
- /*
- * We currently use LTR L1.2 threshold to be fixed constant picked from
- * Intel's coreboot.
- */
- link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS;
+ t_common_mode = max(val1, val2);
/* Choose the greater of the two Port T_POWER_ON times */
val1 = (upreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
@@ -472,10 +477,27 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
scale2 = (dwreg->l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
if (calc_l1ss_pwron(link->pdev, scale1, val1) >
- calc_l1ss_pwron(link->downstream, scale2, val2))
+ calc_l1ss_pwron(link->downstream, scale2, val2)) {
link->l1ss.ctl2 |= scale1 | (val1 << 3);
- else
+ t_power_on = calc_l1ss_pwron(link->pdev, scale1, val1);
+ } else {
link->l1ss.ctl2 |= scale2 | (val2 << 3);
+ t_power_on = calc_l1ss_pwron(link->downstream, scale2, val2);
+ }
+
+ /*
+ * Set LTR_L1.2_THRESHOLD to the time required to transition the
+ * Link from L0 to L1.2 and back to L0 so we enter L1.2 only if
+ * downstream devices report (via LTR) that they can tolerate at
+ * least that much latency.
+ *
+ * Based on PCIe r3.1, sec 5.5.3.3.1, Figures 5-16 and 5-17, and
+ * Table 5-11. T(POWER_OFF) is at most 2us and T(L1.2) is at
+ * least 4us.
+ */
+ l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
+ encode_l12_threshold(l1_2_threshold, &scale, &value);
+ link->l1ss.ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
}
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
@@ -786,7 +808,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
*/
pcie_capability_read_dword(child, PCI_EXP_DEVCAP, &reg32);
if (!(reg32 & PCI_EXP_DEVCAP_RBER) && !aspm_force) {
- dev_info(&child->dev, "disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force'\n");
+ pci_info(child, "disabling ASPM on pre-1.1 PCIe device. You can enable it with 'pcie_aspm=force'\n");
return -EINVAL;
}
}
@@ -1027,7 +1049,7 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
* ignored in this situation.
*/
if (aspm_disabled) {
- dev_warn(&pdev->dev, "can't disable ASPM; OS doesn't have ASPM control\n");
+ pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
return;
}
diff --git a/drivers/pci/pcie/pcie-dpc.c b/drivers/pci/pcie/pcie-dpc.c
index 2d976a623ddc..38e40c6c576f 100644
--- a/drivers/pci/pcie/pcie-dpc.c
+++ b/drivers/pci/pcie/pcie-dpc.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCI Express Downstream Port Containment services driver
* Author: Keith Busch <keith.busch@intel.com>
*
* Copyright (C) 2016 Intel Corp.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
*/
#include <linux/delay.h>
@@ -15,34 +12,15 @@
#include <linux/pci.h>
#include <linux/pcieport_if.h>
#include "../pci.h"
-
-struct rp_pio_header_log_regs {
- u32 dw0;
- u32 dw1;
- u32 dw2;
- u32 dw3;
-};
-
-struct dpc_rp_pio_regs {
- u32 status;
- u32 mask;
- u32 severity;
- u32 syserror;
- u32 exception;
-
- struct rp_pio_header_log_regs header_log;
- u32 impspec_log;
- u32 tlp_prefix_log[4];
- u32 log_size;
- u16 first_error;
-};
+#include "aer/aerdrv.h"
struct dpc_dev {
struct pcie_device *dev;
struct work_struct work;
- int cap_pos;
- bool rp;
+ u16 cap_pos;
+ bool rp_extensions;
u32 rp_pio_status;
+ u8 rp_log_size;
};
static const char * const rp_pio_error_string[] = {
@@ -72,13 +50,13 @@ static int dpc_wait_rp_inactive(struct dpc_dev *dpc)
unsigned long timeout = jiffies + HZ;
struct pci_dev *pdev = dpc->dev->port;
struct device *dev = &dpc->dev->device;
- u16 status;
+ u16 cap = dpc->cap_pos, status;
- pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status);
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
while (status & PCI_EXP_DPC_RP_BUSY &&
!time_after(jiffies, timeout)) {
msleep(10);
- pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status);
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
}
if (status & PCI_EXP_DPC_RP_BUSY) {
dev_warn(dev, "DPC root port still busy\n");
@@ -104,11 +82,12 @@ static void dpc_wait_link_inactive(struct dpc_dev *dpc)
dev_warn(dev, "Link state not disabled for DPC event\n");
}
-static void interrupt_event_handler(struct work_struct *work)
+static void dpc_work(struct work_struct *work)
{
struct dpc_dev *dpc = container_of(work, struct dpc_dev, work);
struct pci_dev *dev, *temp, *pdev = dpc->dev->port;
struct pci_bus *parent = pdev->subordinate;
+ u16 cap = dpc->cap_pos, ctl;
pci_lock_rescan_remove();
list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
@@ -124,159 +103,127 @@ static void interrupt_event_handler(struct work_struct *work)
pci_unlock_rescan_remove();
dpc_wait_link_inactive(dpc);
- if (dpc->rp && dpc_wait_rp_inactive(dpc))
+ if (dpc->rp_extensions && dpc_wait_rp_inactive(dpc))
return;
- if (dpc->rp && dpc->rp_pio_status) {
- pci_write_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS,
- dpc->rp_pio_status);
+ if (dpc->rp_extensions && dpc->rp_pio_status) {
+ pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS,
+ dpc->rp_pio_status);
dpc->rp_pio_status = 0;
}
- pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS,
+ pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT);
-}
-static void dpc_rp_pio_print_tlp_header(struct device *dev,
- struct rp_pio_header_log_regs *t)
-{
- dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n",
- t->dw0, t->dw1, t->dw2, t->dw3);
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl);
+ pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL,
+ ctl | PCI_EXP_DPC_CTL_INT_EN);
}
-static void dpc_rp_pio_print_error(struct dpc_dev *dpc,
- struct dpc_rp_pio_regs *rp_pio)
+static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
{
struct device *dev = &dpc->dev->device;
+ struct pci_dev *pdev = dpc->dev->port;
+ u16 cap = dpc->cap_pos, dpc_status, first_error;
+ u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix;
int i;
- u32 status;
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_MASK, &mask);
dev_err(dev, "rp_pio_status: %#010x, rp_pio_mask: %#010x\n",
- rp_pio->status, rp_pio->mask);
+ status, mask);
+ dpc->rp_pio_status = status;
+
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SEVERITY, &sev);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_SYSERROR, &syserr);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_EXCEPTION, &exc);
dev_err(dev, "RP PIO severity=%#010x, syserror=%#010x, exception=%#010x\n",
- rp_pio->severity, rp_pio->syserror, rp_pio->exception);
+ sev, syserr, exc);
- status = (rp_pio->status & ~rp_pio->mask);
+ /* Get First Error Pointer */
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &dpc_status);
+ first_error = (dpc_status & 0x1f00) >> 8;
+ status &= ~mask;
for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) {
- if (!(status & (1 << i)))
- continue;
-
- dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i],
- rp_pio->first_error == i ? " (First)" : "");
+ if (status & (1 << i))
+ dev_err(dev, "[%2d] %s%s\n", i, rp_pio_error_string[i],
+ first_error == i ? " (First)" : "");
}
- dpc_rp_pio_print_tlp_header(dev, &rp_pio->header_log);
- if (rp_pio->log_size == 4)
+ if (dpc->rp_log_size < 4)
return;
- dev_err(dev, "RP PIO ImpSpec Log %#010x\n", rp_pio->impspec_log);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG,
+ &dw0);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4,
+ &dw1);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8,
+ &dw2);
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12,
+ &dw3);
+ dev_err(dev, "TLP Header: %#010x %#010x %#010x %#010x\n",
+ dw0, dw1, dw2, dw3);
+
+ if (dpc->rp_log_size < 5)
+ return;
+ pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);
+ dev_err(dev, "RP PIO ImpSpec Log %#010x\n", log);
- for (i = 0; i < rp_pio->log_size - 5; i++)
- dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i,
- rp_pio->tlp_prefix_log[i]);
+ for (i = 0; i < dpc->rp_log_size - 5; i++) {
+ pci_read_config_dword(pdev,
+ cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix);
+ dev_err(dev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
+ }
}
-static void dpc_rp_pio_get_info(struct dpc_dev *dpc,
- struct dpc_rp_pio_regs *rp_pio)
+static irqreturn_t dpc_irq(int irq, void *context)
{
+ struct dpc_dev *dpc = (struct dpc_dev *)context;
struct pci_dev *pdev = dpc->dev->port;
struct device *dev = &dpc->dev->device;
- int i;
- u16 cap;
- u16 status;
-
- pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_STATUS,
- &rp_pio->status);
- pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_MASK,
- &rp_pio->mask);
-
- pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_SEVERITY,
- &rp_pio->severity);
- pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_SYSERROR,
- &rp_pio->syserror);
- pci_read_config_dword(pdev, dpc->cap_pos + PCI_EXP_DPC_RP_PIO_EXCEPTION,
- &rp_pio->exception);
-
- /* Get First Error Pointer */
- pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status);
- rp_pio->first_error = (status & 0x1f00) >> 8;
+ u16 cap = dpc->cap_pos, ctl, status, source, reason, ext_reason;
- pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap);
- rp_pio->log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8;
- if (rp_pio->log_size < 4 || rp_pio->log_size > 9) {
- dev_err(dev, "RP PIO log size %u is invalid\n",
- rp_pio->log_size);
- return;
- }
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl);
- pci_read_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG,
- &rp_pio->header_log.dw0);
- pci_read_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4,
- &rp_pio->header_log.dw1);
- pci_read_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8,
- &rp_pio->header_log.dw2);
- pci_read_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12,
- &rp_pio->header_log.dw3);
- if (rp_pio->log_size == 4)
- return;
+ if (!(ctl & PCI_EXP_DPC_CTL_INT_EN) || ctl == (u16)(~0))
+ return IRQ_NONE;
- pci_read_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG,
- &rp_pio->impspec_log);
- for (i = 0; i < rp_pio->log_size - 5; i++)
- pci_read_config_dword(pdev,
- dpc->cap_pos + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG,
- &rp_pio->tlp_prefix_log[i]);
-}
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status);
-static void dpc_process_rp_pio_error(struct dpc_dev *dpc)
-{
- struct dpc_rp_pio_regs rp_pio_regs;
+ if (!(status & PCI_EXP_DPC_STATUS_INTERRUPT))
+ return IRQ_NONE;
- dpc_rp_pio_get_info(dpc, &rp_pio_regs);
- dpc_rp_pio_print_error(dpc, &rp_pio_regs);
+ if (!(status & PCI_EXP_DPC_STATUS_TRIGGER)) {
+ pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
+ PCI_EXP_DPC_STATUS_INTERRUPT);
+ return IRQ_HANDLED;
+ }
- dpc->rp_pio_status = rp_pio_regs.status;
-}
+ pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL,
+ ctl & ~PCI_EXP_DPC_CTL_INT_EN);
-static irqreturn_t dpc_irq(int irq, void *context)
-{
- struct dpc_dev *dpc = (struct dpc_dev *)context;
- struct pci_dev *pdev = dpc->dev->port;
- struct device *dev = &dpc->dev->device;
- u16 status, source;
-
- pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status);
- pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_SOURCE_ID,
+ pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID,
&source);
- if (!status || status == (u16)(~0))
- return IRQ_NONE;
dev_info(dev, "DPC containment event, status:%#06x source:%#06x\n",
status, source);
- if (status & PCI_EXP_DPC_STATUS_TRIGGER) {
- u16 reason = (status >> 1) & 0x3;
- u16 ext_reason = (status >> 5) & 0x3;
-
- dev_warn(dev, "DPC %s detected, remove downstream devices\n",
- (reason == 0) ? "unmasked uncorrectable error" :
- (reason == 1) ? "ERR_NONFATAL" :
- (reason == 2) ? "ERR_FATAL" :
- (ext_reason == 0) ? "RP PIO error" :
- (ext_reason == 1) ? "software trigger" :
- "reserved error");
- /* show RP PIO error detail information */
- if (reason == 3 && ext_reason == 0)
- dpc_process_rp_pio_error(dpc);
-
- schedule_work(&dpc->work);
- }
+ reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1;
+ ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5;
+
+ dev_warn(dev, "DPC %s detected, remove downstream devices\n",
+ (reason == 0) ? "unmasked uncorrectable error" :
+ (reason == 1) ? "ERR_NONFATAL" :
+ (reason == 2) ? "ERR_FATAL" :
+ (ext_reason == 0) ? "RP PIO error" :
+ (ext_reason == 1) ? "software trigger" :
+ "reserved error");
+ /* show RP PIO error detail information */
+ if (dpc->rp_extensions && reason == 3 && ext_reason == 0)
+ dpc_process_rp_pio_error(dpc);
+
+ schedule_work(&dpc->work);
+
return IRQ_HANDLED;
}
@@ -289,13 +236,16 @@ static int dpc_probe(struct pcie_device *dev)
int status;
u16 ctl, cap;
+ if (pcie_aer_get_firmware_first(pdev))
+ return -ENOTSUPP;
+
dpc = devm_kzalloc(device, sizeof(*dpc), GFP_KERNEL);
if (!dpc)
return -ENOMEM;
dpc->cap_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC);
dpc->dev = dev;
- INIT_WORK(&dpc->work, interrupt_event_handler);
+ INIT_WORK(&dpc->work, dpc_work);
set_service_data(dev, dpc);
status = devm_request_irq(device, dev->irq, dpc_irq, IRQF_SHARED,
@@ -309,15 +259,23 @@ static int dpc_probe(struct pcie_device *dev)
pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CAP, &cap);
pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, &ctl);
- dpc->rp = (cap & PCI_EXP_DPC_CAP_RP_EXT);
+ dpc->rp_extensions = (cap & PCI_EXP_DPC_CAP_RP_EXT);
+ if (dpc->rp_extensions) {
+ dpc->rp_log_size = (cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8;
+ if (dpc->rp_log_size < 4 || dpc->rp_log_size > 9) {
+ dev_err(device, "RP PIO log size %u is invalid\n",
+ dpc->rp_log_size);
+ dpc->rp_log_size = 0;
+ }
+ }
ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_NONFATAL | PCI_EXP_DPC_CTL_INT_EN;
pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_CTL, ctl);
dev_info(device, "DPC error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
- cap & 0xf, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
+ cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
- FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), (cap >> 8) & 0xf,
+ FLAG(cap, PCI_EXP_DPC_CAP_SW_TRIGGER), dpc->rp_log_size,
FLAG(cap, PCI_EXP_DPC_CAP_DL_ACTIVE));
return status;
}
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index df290aa58dce..5480f54f7612 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCIe Native PME support
*
* Copyright (C) 2007 - 2009 Intel Corp
* Copyright (C) 2007 - 2009 Shaohua Li <shaohua.li@intel.com>
* Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License V2. See the file "COPYING" in the main directory of this archive
- * for more details.
*/
#include <linux/pci.h>
@@ -198,14 +195,14 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
* assuming that the PME was reported by a PCIe-PCI bridge that
* used devfn different from zero.
*/
- dev_dbg(&port->dev, "PME interrupt generated for non-existent device %02x:%02x.%d\n",
+ pci_dbg(port, "PME interrupt generated for non-existent device %02x:%02x.%d\n",
busnr, PCI_SLOT(devfn), PCI_FUNC(devfn));
found = pcie_pme_from_pci_bridge(bus, 0);
}
out:
if (!found)
- dev_dbg(&port->dev, "Spurious native PME interrupt!\n");
+ pci_dbg(port, "Spurious native PME interrupt!\n");
}
/**
@@ -345,7 +342,7 @@ static int pcie_pme_probe(struct pcie_device *srv)
return ret;
}
- dev_info(&port->dev, "Signaling PME with IRQ %d\n", srv->irq);
+ pci_info(port, "Signaling PME with IRQ %d\n", srv->irq);
pcie_pme_mark_devices(port);
pcie_pme_interrupt_enable(port, true);
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c
index 6b8c2f1d0e71..319c94976873 100644
--- a/drivers/pci/pcie/portdrv_acpi.c
+++ b/drivers/pci/pcie/portdrv_acpi.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCIe Port Native Services Support, ACPI-Related Part
*
* Copyright (C) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License V2. See the file "COPYING" in the main directory of this archive
- * for more details.
*/
#include <linux/pci.h>
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
index 87e79a6ffb5a..f0fba552a0e2 100644
--- a/drivers/pci/pcie/portdrv_bus.c
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* File: portdrv_bus.c
* Purpose: PCI Express Port Bus Driver's Bus Overloading Functions
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index a59210350c44..ef3bad4ad010 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -216,9 +216,9 @@ static int get_port_device_capability(struct pci_dev *dev)
return 0;
cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
- | PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_DPC;
+ | PCIE_PORT_SERVICE_VC;
if (pci_aer_available())
- cap_mask |= PCIE_PORT_SERVICE_AER;
+ cap_mask |= PCIE_PORT_SERVICE_AER | PCIE_PORT_SERVICE_DPC;
if (pcie_ports_auto)
pcie_port_platform_notify(dev, &cap_mask);
diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c
index bab8ac63c4f3..98cfa30f3fae 100644
--- a/drivers/pci/pcie/ptm.c
+++ b/drivers/pci/pcie/ptm.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* PCI Express Precision Time Measurement
* Copyright (c) 2016, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
#include <linux/module.h>
@@ -33,7 +25,7 @@ static void pci_ptm_info(struct pci_dev *dev)
dev->ptm_granularity);
break;
}
- dev_info(&dev->dev, "PTM enabled%s, %s granularity\n",
+ pci_info(dev, "PTM enabled%s, %s granularity\n",
dev->ptm_root ? " (root)" : "", clock_desc);
}