aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/bw_notification.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-09 14:57:08 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-09 14:57:08 -0800
commit2901752c14b8e1b7dd898d2e5245c93e531aa624 (patch)
tree98780bc17593a3d79e7b3fe2ecf23f2e8882a39a /drivers/pci/pcie/bw_notification.c
parent96a6de1a541c86e9e67b9c310c14db4099bd1cbc (diff)
parentdd92b6677e3d0d78e261a7f00f28e753bab41d24 (diff)
downloadlinux-2901752c14b8e1b7dd898d2e5245c93e531aa624.tar.gz
Merge tag 'pci-v5.1-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas: - Use match_string() instead of reimplementing it (Andy Shevchenko) - Enable SERR# forwarding for all bridges (Bharat Kumar Gogada) - Use Latency Tolerance Reporting if already enabled by platform (Bjorn Helgaas) - Save/restore LTR info for suspend/resume (Bjorn Helgaas) - Fix DPC use of uninitialized data (Dongdong Liu) - Probe bridge window attributes only once at enumeration-time to fix device accesses during rescan (Bjorn Helgaas) - Return BAR size (not "size -1 ") from pci_size() to simplify code (Du Changbin) - Use config header type (not class code) identify bridges more reliably (Honghui Zhang) - Work around Intel Denverton incorrect Trace Hub BAR size reporting (Alexander Shishkin) - Reorder pciehp cached state/hardware state updates to avoid missed interrupts (Mika Westerberg) - Turn ibmphp semaphores into completions or mutexes (Arnd Bergmann) - Mark expected switch fall-through (Mathieu Malaterre) - Use of_node_name_eq() for node name comparisons (Rob Herring) - Add ACS and pciehp quirks for HXT SD4800 (Shunyong Yang) - Consolidate Rohm Vendor ID definitions (Andy Shevchenko) - Use u32 (not __u32) for things not exposed to userspace (Logan Gunthorpe) - Fix locking semantics of bus and slot reset interfaces (Alex Williamson) - Update PCIEPORTBUS Kconfig help text (Hou Zhiqiang) - Allow portdrv to claim subtractive decode Ports so PCIe services will work for them (Honghui Zhang) - Report PCIe links that become degraded at run-time (Alexandru Gagniuc) - Blacklist Gigabyte X299 Root Port power management to fix Thunderbolt hotplug (Mika Westerberg) - Revert runtime PM suspend/resume callbacks that broke PME on network cable plug (Mika Westerberg) - Disable Data Link State Changed interrupts to prevent wakeup immediately after suspend (Mika Westerberg) - Extend altera to support Stratix 10 (Ley Foon Tan) - Allow building altera driver on ARM64 (Ley Foon Tan) - Replace Douglas with Tom Joseph as Cadence PCI host/endpoint maintainer (Lorenzo Pieralisi) - Add DT support for R-Car RZ/G2E (R8A774C0) (Fabrizio Castro) - Add dra72x/dra74x/dra76x SoC compatible strings (Kishon Vijay Abraham I) - Enable x2 mode support for dra72x/dra74x/dra76x SoC (Kishon Vijay Abraham I) - Configure dra7xx PHY to PCIe mode (Kishon Vijay Abraham I) - Simplify dwc (remove unnecessary header includes, name variables consistently, reduce inverted logic, etc) (Gustavo Pimentel) - Add i.MX8MQ support (Andrey Smirnov) - Add message to help debug dwc MSI-X mask bit errors (Gustavo Pimentel) - Work around imx7d PCIe PLL erratum (Trent Piepho) - Don't assert qcom reset GPIO during probe (Bjorn Andersson) - Skip dwc MSI init if MSIs have been disabled (Lucas Stach) - Use memcpy_fromio()/memcpy_toio() instead of plain memcpy() in PCI endpoint framework (Wen Yang) - Add interface to discover supported endpoint features to replace a bitfield that wasn't flexible enough (Kishon Vijay Abraham I) - Implement the new supported-feature interface for designware-plat, dra7xx, rockchip, cadence (Kishon Vijay Abraham I) - Fix issues with 64-bit BAR in endpoints (Kishon Vijay Abraham I) - Add layerscape endpoint mode support (Xiaowei Bao) - Remove duplicate struct hv_vp_set in favor of struct hv_vpset (Maya Nakamura) - Rework hv_irq_unmask() to use cpumask_to_vpset() instead of open-coded reimplementation (Maya Nakamura) - Align Hyper-V struct retarget_msi_interrupt arguments (Maya Nakamura) - Fix mediatek MMIO size computation to enable full size of available MMIO space (Honghui Zhang) - Fix mediatek DMA window size computation to allow endpoint DMA access to full DRAM address range (Honghui Zhang) - Fix mvebu prefetchable BAR regression caused by common bridge emulation that assumed all bridges had prefetchable windows (Thomas Petazzoni) - Make advk_pci_bridge_emul_ops static (Wei Yongjun) - Configure MPS settings for VMD root ports (Jon Derrick) * tag 'pci-v5.1-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (92 commits) PCI: Update PCIEPORTBUS Kconfig help text PCI: Fix "try" semantics of bus and slot reset PCI/LINK: Report degraded links via link bandwidth notification dt-bindings: PCI: altera: Add altr,pcie-root-port-2.0 PCI: altera: Enable driver on ARM64 PCI: altera: Add Stratix 10 PCIe support PCI/PME: Fix possible use-after-free on remove PCI: aardvark: Make symbol 'advk_pci_bridge_emul_ops' static PCI: dwc: skip MSI init if MSIs have been explicitly disabled PCI: hv: Refactor hv_irq_unmask() to use cpumask_to_vpset() PCI: hv: Replace hv_vp_set with hv_vpset PCI: hv: Add __aligned(8) to struct retarget_msi_interrupt PCI: mediatek: Enlarge PCIe2AHB window size to support 4GB DRAM PCI: mediatek: Fix memory mapped IO range size computation PCI: dwc: Remove superfluous shifting in definitions PCI: dwc: Make use of GENMASK/FIELD_PREP PCI: dwc: Make use of BIT() in constant definitions PCI: dwc: Share code for dw_pcie_rd/wr_other_conf() PCI: dwc: Make use of IS_ALIGNED() PCI: imx6: Add code to request/control "pcie_aux" clock for i.MX8MQ ...
Diffstat (limited to 'drivers/pci/pcie/bw_notification.c')
-rw-r--r--drivers/pci/pcie/bw_notification.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/pci/pcie/bw_notification.c b/drivers/pci/pcie/bw_notification.c
new file mode 100644
index 000000000000..d2eae3b7cc0f
--- /dev/null
+++ b/drivers/pci/pcie/bw_notification.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PCI Express Link Bandwidth Notification services driver
+ * Author: Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ *
+ * Copyright (C) 2019, Dell Inc
+ *
+ * The PCIe Link Bandwidth Notification provides a way to notify the
+ * operating system when the link width or data rate changes. This
+ * capability is required for all root ports and downstream ports
+ * supporting links wider than x1 and/or multiple link speeds.
+ *
+ * This service port driver hooks into the bandwidth notification interrupt
+ * and warns when links become degraded in operation.
+ */
+
+#include "../pci.h"
+#include "portdrv.h"
+
+static bool pcie_link_bandwidth_notification_supported(struct pci_dev *dev)
+{
+ int ret;
+ u32 lnk_cap;
+
+ ret = pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnk_cap);
+ return (ret == PCIBIOS_SUCCESSFUL) && (lnk_cap & PCI_EXP_LNKCAP_LBNC);
+}
+
+static void pcie_enable_link_bandwidth_notification(struct pci_dev *dev)
+{
+ u16 lnk_ctl;
+
+ pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl);
+ lnk_ctl |= PCI_EXP_LNKCTL_LBMIE;
+ pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl);
+}
+
+static void pcie_disable_link_bandwidth_notification(struct pci_dev *dev)
+{
+ u16 lnk_ctl;
+
+ pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl);
+ lnk_ctl &= ~PCI_EXP_LNKCTL_LBMIE;
+ pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl);
+}
+
+static irqreturn_t pcie_bw_notification_handler(int irq, void *context)
+{
+ struct pcie_device *srv = context;
+ struct pci_dev *port = srv->port;
+ struct pci_dev *dev;
+ u16 link_status, events;
+ int ret;
+
+ ret = pcie_capability_read_word(port, PCI_EXP_LNKSTA, &link_status);
+ events = link_status & PCI_EXP_LNKSTA_LBMS;
+
+ if (ret != PCIBIOS_SUCCESSFUL || !events)
+ return IRQ_NONE;
+
+ /*
+ * Print status from downstream devices, not this root port or
+ * downstream switch port.
+ */
+ down_read(&pci_bus_sem);
+ list_for_each_entry(dev, &port->subordinate->devices, bus_list)
+ __pcie_print_link_status(dev, false);
+ up_read(&pci_bus_sem);
+
+ pcie_update_link_speed(port->subordinate, link_status);
+ pcie_capability_write_word(port, PCI_EXP_LNKSTA, events);
+ return IRQ_HANDLED;
+}
+
+static int pcie_bandwidth_notification_probe(struct pcie_device *srv)
+{
+ int ret;
+
+ /* Single-width or single-speed ports do not have to support this. */
+ if (!pcie_link_bandwidth_notification_supported(srv->port))
+ return -ENODEV;
+
+ ret = request_threaded_irq(srv->irq, NULL, pcie_bw_notification_handler,
+ IRQF_SHARED, "PCIe BW notif", srv);
+ if (ret)
+ return ret;
+
+ pcie_enable_link_bandwidth_notification(srv->port);
+
+ return 0;
+}
+
+static void pcie_bandwidth_notification_remove(struct pcie_device *srv)
+{
+ pcie_disable_link_bandwidth_notification(srv->port);
+ free_irq(srv->irq, srv);
+}
+
+static struct pcie_port_service_driver pcie_bandwidth_notification_driver = {
+ .name = "pcie_bw_notification",
+ .port_type = PCIE_ANY_PORT,
+ .service = PCIE_PORT_SERVICE_BWNOTIF,
+ .probe = pcie_bandwidth_notification_probe,
+ .remove = pcie_bandwidth_notification_remove,
+};
+
+int __init pcie_bandwidth_notification_init(void)
+{
+ return pcie_port_service_register(&pcie_bandwidth_notification_driver);
+}