Commit 9936328b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pci-v5.1-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI fixes from Bjorn Helgaas:
 "PCI fixes:

   - Clear level-triggered interrupts for the bandwidth notification
     supported added for v5.1 (Alexandru Gagniuc)

   - Clear bandwidth notification interrupts before enabling them (Lukas
     Wunner)

   - Report post-enumeration bandwidth changes only once for
     multi-function devices (Lukas Wunner)"

* tag 'pci-v5.1-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  PCI/LINK: Deduplicate bandwidth reports for multi-function devices
  PCI/LINK: Clear bandwidth notification interrupt before enabling it
  PCI/LINK: Supply IRQ handler so level-triggered IRQs are acked
parents 8c7ae38d 0fa635ae
...@@ -273,6 +273,7 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev); ...@@ -273,6 +273,7 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev);
u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed, u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
enum pcie_link_width *width); enum pcie_link_width *width);
void __pcie_print_link_status(struct pci_dev *dev, bool verbose); void __pcie_print_link_status(struct pci_dev *dev, bool verbose);
void pcie_report_downtraining(struct pci_dev *dev);
/* Single Root I/O Virtualization */ /* Single Root I/O Virtualization */
struct pci_sriov { struct pci_sriov {
......
...@@ -30,6 +30,8 @@ static void pcie_enable_link_bandwidth_notification(struct pci_dev *dev) ...@@ -30,6 +30,8 @@ static void pcie_enable_link_bandwidth_notification(struct pci_dev *dev)
{ {
u16 lnk_ctl; 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); pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl);
lnk_ctl |= PCI_EXP_LNKCTL_LBMIE; lnk_ctl |= PCI_EXP_LNKCTL_LBMIE;
pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl); pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl);
...@@ -44,11 +46,10 @@ static void pcie_disable_link_bandwidth_notification(struct pci_dev *dev) ...@@ -44,11 +46,10 @@ static void pcie_disable_link_bandwidth_notification(struct pci_dev *dev)
pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl); pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl);
} }
static irqreturn_t pcie_bw_notification_handler(int irq, void *context) static irqreturn_t pcie_bw_notification_irq(int irq, void *context)
{ {
struct pcie_device *srv = context; struct pcie_device *srv = context;
struct pci_dev *port = srv->port; struct pci_dev *port = srv->port;
struct pci_dev *dev;
u16 link_status, events; u16 link_status, events;
int ret; int ret;
...@@ -58,17 +59,26 @@ static irqreturn_t pcie_bw_notification_handler(int irq, void *context) ...@@ -58,17 +59,26 @@ static irqreturn_t pcie_bw_notification_handler(int irq, void *context)
if (ret != PCIBIOS_SUCCESSFUL || !events) if (ret != PCIBIOS_SUCCESSFUL || !events)
return IRQ_NONE; 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 * Print status from downstream devices, not this root port or
* downstream switch port. * downstream switch port.
*/ */
down_read(&pci_bus_sem); down_read(&pci_bus_sem);
list_for_each_entry(dev, &port->subordinate->devices, bus_list) list_for_each_entry(dev, &port->subordinate->devices, bus_list)
__pcie_print_link_status(dev, false); pcie_report_downtraining(dev);
up_read(&pci_bus_sem); 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; return IRQ_HANDLED;
} }
...@@ -80,7 +90,8 @@ static int pcie_bandwidth_notification_probe(struct pcie_device *srv) ...@@ -80,7 +90,8 @@ static int pcie_bandwidth_notification_probe(struct pcie_device *srv)
if (!pcie_link_bandwidth_notification_supported(srv->port)) if (!pcie_link_bandwidth_notification_supported(srv->port))
return -ENODEV; return -ENODEV;
ret = request_threaded_irq(srv->irq, NULL, pcie_bw_notification_handler, ret = request_threaded_irq(srv->irq, pcie_bw_notification_irq,
pcie_bw_notification_handler,
IRQF_SHARED, "PCIe BW notif", srv); IRQF_SHARED, "PCIe BW notif", srv);
if (ret) if (ret)
return ret; return ret;
......
...@@ -2388,7 +2388,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) ...@@ -2388,7 +2388,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
return dev; return dev;
} }
static void pcie_report_downtraining(struct pci_dev *dev) void pcie_report_downtraining(struct pci_dev *dev)
{ {
if (!pci_is_pcie(dev)) if (!pci_is_pcie(dev))
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment