1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#define dev_fmt(fmt) "bw_notification: " fmt
18
19#include "../pci.h"
20#include "portdrv.h"
21
22static bool pcie_link_bandwidth_notification_supported(struct pci_dev *dev)
23{
24 int ret;
25 u32 lnk_cap;
26
27 ret = pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnk_cap);
28 return (ret == PCIBIOS_SUCCESSFUL) && (lnk_cap & PCI_EXP_LNKCAP_LBNC);
29}
30
31static void pcie_enable_link_bandwidth_notification(struct pci_dev *dev)
32{
33 u16 lnk_ctl;
34
35 pcie_capability_write_word(dev, PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_LBMS);
36
37 pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl);
38 lnk_ctl |= PCI_EXP_LNKCTL_LBMIE;
39 pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl);
40}
41
42static void pcie_disable_link_bandwidth_notification(struct pci_dev *dev)
43{
44 u16 lnk_ctl;
45
46 pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnk_ctl);
47 lnk_ctl &= ~PCI_EXP_LNKCTL_LBMIE;
48 pcie_capability_write_word(dev, PCI_EXP_LNKCTL, lnk_ctl);
49}
50
51static irqreturn_t pcie_bw_notification_irq(int irq, void *context)
52{
53 struct pcie_device *srv = context;
54 struct pci_dev *port = srv->port;
55 u16 link_status, events;
56 int ret;
57
58 ret = pcie_capability_read_word(port, PCI_EXP_LNKSTA, &link_status);
59 events = link_status & PCI_EXP_LNKSTA_LBMS;
60
61 if (ret != PCIBIOS_SUCCESSFUL || !events)
62 return IRQ_NONE;
63
64 pcie_capability_write_word(port, PCI_EXP_LNKSTA, events);
65 pcie_update_link_speed(port->subordinate, link_status);
66 return IRQ_WAKE_THREAD;
67}
68
69static irqreturn_t pcie_bw_notification_handler(int irq, void *context)
70{
71 struct pcie_device *srv = context;
72 struct pci_dev *port = srv->port;
73 struct pci_dev *dev;
74
75
76
77
78
79 down_read(&pci_bus_sem);
80 list_for_each_entry(dev, &port->subordinate->devices, bus_list)
81 pcie_report_downtraining(dev);
82 up_read(&pci_bus_sem);
83
84 return IRQ_HANDLED;
85}
86
87static int pcie_bandwidth_notification_probe(struct pcie_device *srv)
88{
89 int ret;
90
91
92 if (!pcie_link_bandwidth_notification_supported(srv->port))
93 return -ENODEV;
94
95 ret = request_threaded_irq(srv->irq, pcie_bw_notification_irq,
96 pcie_bw_notification_handler,
97 IRQF_SHARED, "PCIe BW notif", srv);
98 if (ret)
99 return ret;
100
101 pcie_enable_link_bandwidth_notification(srv->port);
102 pci_info(srv->port, "enabled with IRQ %d\n", srv->irq);
103
104 return 0;
105}
106
107static void pcie_bandwidth_notification_remove(struct pcie_device *srv)
108{
109 pcie_disable_link_bandwidth_notification(srv->port);
110 free_irq(srv->irq, srv);
111}
112
113static int pcie_bandwidth_notification_suspend(struct pcie_device *srv)
114{
115 pcie_disable_link_bandwidth_notification(srv->port);
116 return 0;
117}
118
119static int pcie_bandwidth_notification_resume(struct pcie_device *srv)
120{
121 pcie_enable_link_bandwidth_notification(srv->port);
122 return 0;
123}
124
125static struct pcie_port_service_driver pcie_bandwidth_notification_driver = {
126 .name = "pcie_bw_notification",
127 .port_type = PCIE_ANY_PORT,
128 .service = PCIE_PORT_SERVICE_BWNOTIF,
129 .probe = pcie_bandwidth_notification_probe,
130 .suspend = pcie_bandwidth_notification_suspend,
131 .resume = pcie_bandwidth_notification_resume,
132 .remove = pcie_bandwidth_notification_remove,
133};
134
135int __init pcie_bandwidth_notification_init(void)
136{
137 return pcie_port_service_register(&pcie_bandwidth_notification_driver);
138}
139