diff options
| -rw-r--r-- | drivers/pci/pci.h | 1 | ||||
| -rw-r--r-- | drivers/pci/pcie/bw_notification.c | 23 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 2 |
3 files changed, 19 insertions, 7 deletions
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 224d88634115..d994839a3e24 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -273,6 +273,7 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev); | |||
| 273 | u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed, | 273 | u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed, |
| 274 | enum pcie_link_width *width); | 274 | enum pcie_link_width *width); |
| 275 | void __pcie_print_link_status(struct pci_dev *dev, bool verbose); | 275 | void __pcie_print_link_status(struct pci_dev *dev, bool verbose); |
| 276 | void pcie_report_downtraining(struct pci_dev *dev); | ||
| 276 | 277 | ||
| 277 | /* Single Root I/O Virtualization */ | 278 | /* Single Root I/O Virtualization */ |
| 278 | struct pci_sriov { | 279 | struct pci_sriov { |
diff --git a/drivers/pci/pcie/bw_notification.c b/drivers/pci/pcie/bw_notification.c index d2eae3b7cc0f..4fa9e3523ee1 100644 --- a/drivers/pci/pcie/bw_notification.c +++ b/drivers/pci/pcie/bw_notification.c | |||
| @@ -30,6 +30,8 @@ static void pcie_enable_link_bandwidth_notification(struct pci_dev *dev) | |||
| 30 | { | 30 | { |
| 31 | u16 lnk_ctl; | 31 | u16 lnk_ctl; |
| 32 | 32 | ||
| 33 | pcie_capability_write_word(dev, PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_LBMS); | ||
| 34 | |||
| 33 | pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl); | 35 | pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl); |
| 34 | lnk_ctl |= PCI_EXP_LNKCTL_LBMIE; | 36 | lnk_ctl |= PCI_EXP_LNKCTL_LBMIE; |
| 35 | pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl); | 37 | 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 | pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl); | 46 | pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl); |
| 45 | } | 47 | } |
| 46 | 48 | ||
| 47 | static irqreturn_t pcie_bw_notification_handler(int irq, void *context) | 49 | static irqreturn_t pcie_bw_notification_irq(int irq, void *context) |
| 48 | { | 50 | { |
| 49 | struct pcie_device *srv = context; | 51 | struct pcie_device *srv = context; |
| 50 | struct pci_dev *port = srv->port; | 52 | struct pci_dev *port = srv->port; |
| 51 | struct pci_dev *dev; | ||
| 52 | u16 link_status, events; | 53 | u16 link_status, events; |
| 53 | int ret; | 54 | int ret; |
| 54 | 55 | ||
| @@ -58,17 +59,26 @@ static irqreturn_t pcie_bw_notification_handler(int irq, void *context) | |||
| 58 | if (ret != PCIBIOS_SUCCESSFUL || !events) | 59 | if (ret != PCIBIOS_SUCCESSFUL || !events) |
| 59 | return IRQ_NONE; | 60 | return IRQ_NONE; |
| 60 | 61 | ||
| 62 | pcie_capability_write_word(port, PCI_EXP_LNKSTA, events); | ||
| 63 | pcie_update_link_speed(port->subordinate, link_status); | ||
| 64 | return IRQ_WAKE_THREAD; | ||
| 65 | } | ||
| 66 | |||
| 67 | static irqreturn_t pcie_bw_notification_handler(int irq, void *context) | ||
| 68 | { | ||
| 69 | struct pcie_device *srv = context; | ||
| 70 | struct pci_dev *port = srv->port; | ||
| 71 | struct pci_dev *dev; | ||
| 72 | |||
| 61 | /* | 73 | /* |
| 62 | * Print status from downstream devices, not this root port or | 74 | * Print status from downstream devices, not this root port or |
| 63 | * downstream switch port. | 75 | * downstream switch port. |
| 64 | */ | 76 | */ |
| 65 | down_read(&pci_bus_sem); | 77 | down_read(&pci_bus_sem); |
| 66 | list_for_each_entry(dev, &port->subordinate->devices, bus_list) | 78 | list_for_each_entry(dev, &port->subordinate->devices, bus_list) |
| 67 | __pcie_print_link_status(dev, false); | 79 | pcie_report_downtraining(dev); |
| 68 | up_read(&pci_bus_sem); | 80 | up_read(&pci_bus_sem); |
| 69 | 81 | ||
| 70 | pcie_update_link_speed(port->subordinate, link_status); | ||
| 71 | pcie_capability_write_word(port, PCI_EXP_LNKSTA, events); | ||
| 72 | return IRQ_HANDLED; | 82 | return IRQ_HANDLED; |
| 73 | } | 83 | } |
| 74 | 84 | ||
| @@ -80,7 +90,8 @@ static int pcie_bandwidth_notification_probe(struct pcie_device *srv) | |||
| 80 | if (!pcie_link_bandwidth_notification_supported(srv->port)) | 90 | if (!pcie_link_bandwidth_notification_supported(srv->port)) |
| 81 | return -ENODEV; | 91 | return -ENODEV; |
| 82 | 92 | ||
| 83 | ret = request_threaded_irq(srv->irq, NULL, pcie_bw_notification_handler, | 93 | ret = request_threaded_irq(srv->irq, pcie_bw_notification_irq, |
| 94 | pcie_bw_notification_handler, | ||
| 84 | IRQF_SHARED, "PCIe BW notif", srv); | 95 | IRQF_SHARED, "PCIe BW notif", srv); |
| 85 | if (ret) | 96 | if (ret) |
| 86 | return ret; | 97 | return ret; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2ec0df04e0dc..7e12d0163863 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
| @@ -2388,7 +2388,7 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) | |||
| 2388 | return dev; | 2388 | return dev; |
| 2389 | } | 2389 | } |
| 2390 | 2390 | ||
| 2391 | static void pcie_report_downtraining(struct pci_dev *dev) | 2391 | void pcie_report_downtraining(struct pci_dev *dev) |
| 2392 | { | 2392 | { |
| 2393 | if (!pci_is_pcie(dev)) | 2393 | if (!pci_is_pcie(dev)) |
| 2394 | return; | 2394 | return; |
