-----BEGIN PGP SIGNATURE-----
iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAlzZ/4MUHGJoZWxnYWFz
QGdvb2dsZS5jb20ACgkQWYigwDrT+vwmYw/+Mzkkz/zOpzYdsYyy6Xv3qRdn92Kp
bePOPACdwpUK+HV4qE6EEYBcVZdkO7NMkshA7wIb4VlsE0sVHSPvlybUmTUGWeFd
CG87YytVOo4K7cAeKdGVwGaoQSeaZX3wmXVGGQtm/T4b63GdBjlNJ/MBuPWDDMlM
XEis29MTH6xAu3MbT7pp5q+snSzOmt0RWuVpX/U1YcZdhu8fbwfOxj9Jx6slh4+2
MvseYNNrTRJrMF0o5o83Khx3tAcW8OTTnDJ9+BCrAlE1PId1s/KjzY6nqReBtom9
CIqtwAlx/wGkRBRgfsmEtFBhkDA05PPilhSy6k2LP8B4A3qBqir1Pd+5bhHG4FIu
nPPCZjZs2+0DNrZwQv59qIlWsqDFm214WRln9Z7d/VNtrLs2UknVghjQcHv7rP+K
/NKfPlAuHTI/AFi9pIPFWTMx5J4iXX1hX4LiptE9M0k9/vSiaCVnTS3QbFvp3py3
VTT9sprzfV4JX4aqS/rbQc/9g4k9OXPW9viOuWf5rYZJTBbsu6PehjUIRECyFaO+
0gDqE8WsQOtNNX7e5q2HJ/HpPQ+Q1IIlReC+1H56T/EQZmSIBwhTLttQMREL/8af
Lka3/1SVUi4WG6SBrBI75ClsR91UzE6AK+h9fAyDuR6XJkbysWjkyG6Lmy617g6w
lb+fQwOzUt4eGDo=
=4Vc+
-----END PGP SIGNATURE-----
Merge tag 'pci-v5.2-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas:
"Enumeration changes:
- Add _HPX Type 3 settings support, which gives firmware more
influence over device configuration (Alexandru Gagniuc)
- Support fixed bus numbers from bridge Enhanced Allocation
capabilities (Subbaraya Sundeep)
- Add "external-facing" DT property to identify cases where we
require IOMMU protection against untrusted devices (Jean-Philippe
Brucker)
- Enable PCIe services for host controller drivers that use managed
host bridge alloc (Jean-Philippe Brucker)
- Log PCIe port service messages with pci_dev, not the pcie_device
(Frederick Lawler)
- Convert pciehp from pciehp_debug module parameter to generic
dynamic debug (Frederick Lawler)
Peer-to-peer DMA:
- Add whitelist of Root Complexes that support peer-to-peer DMA
between Root Ports (Christian König)
Native controller drivers:
- Add PCI host bridge DMA ranges for bridges that can't DMA
everywhere, e.g., iProc (Srinath Mannam)
- Add Amazon Annapurna Labs PCIe host controller driver (Jonathan
Chocron)
- Fix Tegra MSI target allocation so DMA doesn't generate unwanted
MSIs (Vidya Sagar)
- Fix of_node reference leaks (Wen Yang)
- Fix Hyper-V module unload & device removal issues (Dexuan Cui)
- Cleanup R-Car driver (Marek Vasut)
- Cleanup Keystone driver (Kishon Vijay Abraham I)
- Cleanup i.MX6 driver (Andrey Smirnov)
Significant bug fixes:
- Reset Lenovo ThinkPad P50 GPU so nouveau works after reboot (Lyude
Paul)
- Fix Switchtec firmware update performance issue (Wesley Sheng)
- Work around Pericom switch link retraining erratum (Stefan Mätje)"
* tag 'pci-v5.2-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (141 commits)
MAINTAINERS: Add Karthikeyan Mitran and Hou Zhiqiang for Mobiveil PCI
PCI: pciehp: Remove pointless MY_NAME definition
PCI: pciehp: Remove pointless PCIE_MODULE_NAME definition
PCI: pciehp: Remove unused dbg/err/info/warn() wrappers
PCI: pciehp: Log messages with pci_dev, not pcie_device
PCI: pciehp: Replace pciehp_debug module param with dyndbg
PCI: pciehp: Remove pciehp_debug uses
PCI/AER: Log messages with pci_dev, not pcie_device
PCI/DPC: Log messages with pci_dev, not pcie_device
PCI/PME: Replace dev_printk(KERN_DEBUG) with dev_info()
PCI/AER: Replace dev_printk(KERN_DEBUG) with dev_info()
PCI: Replace dev_printk(KERN_DEBUG) with dev_info(), etc
PCI: Replace printk(KERN_INFO) with pr_info(), etc
PCI: Use dev_printk() when possible
PCI: Cleanup setup-bus.c comments and whitespace
PCI: imx6: Allow asynchronous probing
PCI: dwc: Save root bus for driver remove hooks
PCI: dwc: Use devm_pci_alloc_host_bridge() to simplify code
PCI: dwc: Free MSI in dw_pcie_host_init() error path
PCI: dwc: Free MSI IRQ page in dw_pcie_free_msi()
...
136 lines
3.7 KiB
C
136 lines
3.7 KiB
C
// 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_write_word(dev, PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_LBMS);
|
|
|
|
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_irq(int irq, void *context)
|
|
{
|
|
struct pcie_device *srv = context;
|
|
struct pci_dev *port = srv->port;
|
|
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;
|
|
|
|
pcie_capability_write_word(port, PCI_EXP_LNKSTA, events);
|
|
pcie_update_link_speed(port->subordinate, link_status);
|
|
return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
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;
|
|
|
|
/*
|
|
* 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_report_downtraining(dev);
|
|
up_read(&pci_bus_sem);
|
|
|
|
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, pcie_bw_notification_irq,
|
|
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 int pcie_bandwidth_notification_suspend(struct pcie_device *srv)
|
|
{
|
|
pcie_disable_link_bandwidth_notification(srv->port);
|
|
return 0;
|
|
}
|
|
|
|
static int pcie_bandwidth_notification_resume(struct pcie_device *srv)
|
|
{
|
|
pcie_enable_link_bandwidth_notification(srv->port);
|
|
return 0;
|
|
}
|
|
|
|
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,
|
|
.suspend = pcie_bandwidth_notification_suspend,
|
|
.resume = pcie_bandwidth_notification_resume,
|
|
.remove = pcie_bandwidth_notification_remove,
|
|
};
|
|
|
|
int __init pcie_bandwidth_notification_init(void)
|
|
{
|
|
return pcie_port_service_register(&pcie_bandwidth_notification_driver);
|
|
}
|