diff options
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/Kconfig | 3 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/Kconfig.debug | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 22 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 7 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 31 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 27 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/ecrc.c | 16 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 80 | ||||
-rw-r--r-- | drivers/pci/pcie/pcie-dpc.c | 256 | ||||
-rw-r--r-- | drivers/pci/pcie/pme.c | 11 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_acpi.c | 5 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_bus.c | 1 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 4 | ||||
-rw-r--r-- | drivers/pci/pcie/ptm.c | 12 |
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, ®32); 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, ®32); 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); } |