mirror of https://gitee.com/openkylin/linux.git
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: e8303bb7a7
("PCI/LINK: Report degraded links via link bandwidth notification")
Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Reported-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
9e98c678c2
commit
3e82a7f903
|
@ -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);
|
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,6 +57,17 @@ 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.
|
||||||
|
@ -67,8 +77,6 @@ static irqreturn_t pcie_bw_notification_handler(int irq, void *context)
|
||||||
__pcie_print_link_status(dev, false);
|
__pcie_print_link_status(dev, false);
|
||||||
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 +88,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;
|
||||||
|
|
Loading…
Reference in New Issue