Commit 3e82a7f9 authored by Alexandru Gagniuc's avatar Alexandru Gagniuc Committed by Bjorn Helgaas
Browse files

PCI/LINK: Supply IRQ handler so level-triggered IRQs are acked



A threaded IRQ with a NULL handler does not work with level-triggered
interrupts.  request_threaded_irq() will return an error:

  genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq 16
  pcie_bw_notification: probe of 0000:00:1b.0:pcie010 failed with error -22

For level interrupts we need to silence the interrupt before exiting the
IRQ handler, so just clear the PCI_EXP_LNKSTA_LBMS bit there.

Fixes: e8303bb7 ("PCI/LINK: Report degraded links via link bandwidth notification")
Reported-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Reported-by: default avatarBorislav Petkov <bp@suse.de>
Signed-off-by: default avatarAlexandru Gagniuc <mr.nuke.me@gmail.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 9e98c678
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -44,11 +44,10 @@ static void pcie_disable_link_bandwidth_notification(struct pci_dev *dev)
	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 pci_dev *port = srv->port;
	struct pci_dev *dev;
	u16 link_status, events;
	int ret;

@@ -58,6 +57,17 @@ static irqreturn_t pcie_bw_notification_handler(int irq, void *context)
	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.
@@ -67,8 +77,6 @@ static irqreturn_t pcie_bw_notification_handler(int irq, void *context)
		__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;
}

@@ -80,7 +88,8 @@ static int pcie_bandwidth_notification_probe(struct pcie_device *srv)
	if (!pcie_link_bandwidth_notification_supported(srv->port))
		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);
	if (ret)
		return ret;