1
2
3
4
5
6
7
8
9
10#include <linux/pci.h>
11#include <linux/kernel.h>
12#include <linux/errno.h>
13#include <linux/pm.h>
14#include <linux/pm_runtime.h>
15#include <linux/init.h>
16#include <linux/aer.h>
17#include <linux/dmi.h>
18
19#include "../pci.h"
20#include "portdrv.h"
21
22
23bool pcie_ports_disabled;
24
25
26
27
28
29
30bool pcie_ports_native;
31
32static int __init pcie_port_setup(char *str)
33{
34 if (!strncmp(str, "compat", 6))
35 pcie_ports_disabled = true;
36 else if (!strncmp(str, "native", 6))
37 pcie_ports_native = true;
38
39 return 1;
40}
41__setup("pcie_ports=", pcie_port_setup);
42
43
44
45#ifdef CONFIG_PM
46static int pcie_port_runtime_suspend(struct device *dev)
47{
48 if (!to_pci_dev(dev)->bridge_d3)
49 return -EBUSY;
50
51 return pcie_port_device_runtime_suspend(dev);
52}
53
54static int pcie_port_runtime_idle(struct device *dev)
55{
56
57
58
59
60
61 return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
62}
63
64static const struct dev_pm_ops pcie_portdrv_pm_ops = {
65 .suspend = pcie_port_device_suspend,
66 .resume_noirq = pcie_port_device_resume_noirq,
67 .resume = pcie_port_device_resume,
68 .freeze = pcie_port_device_suspend,
69 .thaw = pcie_port_device_resume,
70 .poweroff = pcie_port_device_suspend,
71 .restore_noirq = pcie_port_device_resume_noirq,
72 .restore = pcie_port_device_resume,
73 .runtime_suspend = pcie_port_runtime_suspend,
74 .runtime_resume = pcie_port_device_runtime_resume,
75 .runtime_idle = pcie_port_runtime_idle,
76};
77
78#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
79
80#else
81
82#define PCIE_PORTDRV_PM_OPS NULL
83#endif
84
85
86
87
88
89
90
91
92
93static int pcie_portdrv_probe(struct pci_dev *dev,
94 const struct pci_device_id *id)
95{
96 int status;
97
98 if (!pci_is_pcie(dev) ||
99 ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
100 (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) &&
101 (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
102 return -ENODEV;
103
104 status = pcie_port_device_register(dev);
105 if (status)
106 return status;
107
108 pci_save_state(dev);
109
110 dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_SMART_SUSPEND |
111 DPM_FLAG_LEAVE_SUSPENDED);
112
113 if (pci_bridge_d3_possible(dev)) {
114
115
116
117
118
119 pm_runtime_set_autosuspend_delay(&dev->dev, 100);
120 pm_runtime_use_autosuspend(&dev->dev);
121 pm_runtime_mark_last_busy(&dev->dev);
122 pm_runtime_put_autosuspend(&dev->dev);
123 pm_runtime_allow(&dev->dev);
124 }
125
126 return 0;
127}
128
129static void pcie_portdrv_remove(struct pci_dev *dev)
130{
131 if (pci_bridge_d3_possible(dev)) {
132 pm_runtime_forbid(&dev->dev);
133 pm_runtime_get_noresume(&dev->dev);
134 pm_runtime_dont_use_autosuspend(&dev->dev);
135 }
136
137 pcie_port_device_remove(dev);
138}
139
140static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
141 enum pci_channel_state error)
142{
143
144 return PCI_ERS_RESULT_CAN_RECOVER;
145}
146
147static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
148{
149 return PCI_ERS_RESULT_RECOVERED;
150}
151
152static int resume_iter(struct device *device, void *data)
153{
154 struct pcie_device *pcie_device;
155 struct pcie_port_service_driver *driver;
156
157 if (device->bus == &pcie_port_bus_type && device->driver) {
158 driver = to_service_driver(device->driver);
159 if (driver && driver->error_resume) {
160 pcie_device = to_pcie_device(device);
161
162
163 driver->error_resume(pcie_device->port);
164 }
165 }
166
167 return 0;
168}
169
170static void pcie_portdrv_err_resume(struct pci_dev *dev)
171{
172 device_for_each_child(&dev->dev, NULL, resume_iter);
173}
174
175
176
177
178static const struct pci_device_id port_pci_ids[] = { {
179
180 PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
181 }, { }
182};
183
184static const struct pci_error_handlers pcie_portdrv_err_handler = {
185 .error_detected = pcie_portdrv_error_detected,
186 .mmio_enabled = pcie_portdrv_mmio_enabled,
187 .resume = pcie_portdrv_err_resume,
188};
189
190static struct pci_driver pcie_portdriver = {
191 .name = "pcieport",
192 .id_table = &port_pci_ids[0],
193
194 .probe = pcie_portdrv_probe,
195 .remove = pcie_portdrv_remove,
196 .shutdown = pcie_portdrv_remove,
197
198 .err_handler = &pcie_portdrv_err_handler,
199
200 .driver.pm = PCIE_PORTDRV_PM_OPS,
201};
202
203static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d)
204{
205 pr_notice("%s detected: will not use MSI for PCIe PME signaling\n",
206 d->ident);
207 pcie_pme_disable_msi();
208 return 0;
209}
210
211static const struct dmi_system_id pcie_portdrv_dmi_table[] __initconst = {
212
213
214
215 {
216 .callback = dmi_pcie_pme_disable_msi,
217 .ident = "MSI Wind U-100",
218 .matches = {
219 DMI_MATCH(DMI_SYS_VENDOR,
220 "MICRO-STAR INTERNATIONAL CO., LTD"),
221 DMI_MATCH(DMI_PRODUCT_NAME, "U-100"),
222 },
223 },
224 {}
225};
226
227static int __init pcie_portdrv_init(void)
228{
229 if (pcie_ports_disabled)
230 return -EACCES;
231
232 dmi_check_system(pcie_portdrv_dmi_table);
233
234 return pci_register_driver(&pcie_portdriver);
235}
236device_initcall(pcie_portdrv_init);
237