Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Purpose: PCI Express Port Bus Driver
4 : : * Author: Tom Nguyen <tom.l.nguyen@intel.com>
5 : : *
6 : : * Copyright (C) 2004 Intel
7 : : * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
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 : : /* If this switch is set, PCIe port native services should not be enabled. */
23 : : bool pcie_ports_disabled;
24 : :
25 : : /*
26 : : * If the user specified "pcie_ports=native", use the PCIe services regardless
27 : : * of whether the platform has given us permission. On ACPI systems, this
28 : : * means we ignore _OSC.
29 : : */
30 : : bool pcie_ports_native;
31 : :
32 : : /*
33 : : * If the user specified "pcie_ports=dpc-native", use the Linux DPC PCIe
34 : : * service even if the platform hasn't given us permission.
35 : : */
36 : : bool pcie_ports_dpc_native;
37 : :
38 : 0 : static int __init pcie_port_setup(char *str)
39 : : {
40 [ # # ]: 0 : if (!strncmp(str, "compat", 6))
41 : 0 : pcie_ports_disabled = true;
42 [ # # ]: 0 : else if (!strncmp(str, "native", 6))
43 : 0 : pcie_ports_native = true;
44 [ # # ]: 0 : else if (!strncmp(str, "dpc-native", 10))
45 : 0 : pcie_ports_dpc_native = true;
46 : :
47 : 0 : return 1;
48 : : }
49 : : __setup("pcie_ports=", pcie_port_setup);
50 : :
51 : : /* global data */
52 : :
53 : : #ifdef CONFIG_PM
54 : 0 : static int pcie_port_runtime_suspend(struct device *dev)
55 : : {
56 [ # # ]: 0 : if (!to_pci_dev(dev)->bridge_d3)
57 : : return -EBUSY;
58 : :
59 : 0 : return pcie_port_device_runtime_suspend(dev);
60 : : }
61 : :
62 : 0 : static int pcie_port_runtime_idle(struct device *dev)
63 : : {
64 : : /*
65 : : * Assume the PCI core has set bridge_d3 whenever it thinks the port
66 : : * should be good to go to D3. Everything else, including moving
67 : : * the port to D3, is handled by the PCI core.
68 : : */
69 [ # # ]: 0 : return to_pci_dev(dev)->bridge_d3 ? 0 : -EBUSY;
70 : : }
71 : :
72 : : static const struct dev_pm_ops pcie_portdrv_pm_ops = {
73 : : .suspend = pcie_port_device_suspend,
74 : : .resume_noirq = pcie_port_device_resume_noirq,
75 : : .resume = pcie_port_device_resume,
76 : : .freeze = pcie_port_device_suspend,
77 : : .thaw = pcie_port_device_resume,
78 : : .poweroff = pcie_port_device_suspend,
79 : : .restore_noirq = pcie_port_device_resume_noirq,
80 : : .restore = pcie_port_device_resume,
81 : : .runtime_suspend = pcie_port_runtime_suspend,
82 : : .runtime_resume = pcie_port_device_runtime_resume,
83 : : .runtime_idle = pcie_port_runtime_idle,
84 : : };
85 : :
86 : : #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
87 : :
88 : : #else /* !PM */
89 : :
90 : : #define PCIE_PORTDRV_PM_OPS NULL
91 : : #endif /* !PM */
92 : :
93 : : /*
94 : : * pcie_portdrv_probe - Probe PCI-Express port devices
95 : : * @dev: PCI-Express port device being probed
96 : : *
97 : : * If detected invokes the pcie_port_device_register() method for
98 : : * this port device.
99 : : *
100 : : */
101 : 0 : static int pcie_portdrv_probe(struct pci_dev *dev,
102 : : const struct pci_device_id *id)
103 : : {
104 : 0 : int status;
105 : :
106 [ # # # # ]: 0 : if (!pci_is_pcie(dev) ||
107 [ # # ]: 0 : ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
108 [ # # ]: 0 : (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) &&
109 : : (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
110 : : return -ENODEV;
111 : :
112 : 0 : status = pcie_port_device_register(dev);
113 [ # # ]: 0 : if (status)
114 : : return status;
115 : :
116 : 0 : pci_save_state(dev);
117 : :
118 : 0 : dev_pm_set_driver_flags(&dev->dev, DPM_FLAG_NEVER_SKIP |
119 : : DPM_FLAG_SMART_SUSPEND);
120 : :
121 [ # # ]: 0 : if (pci_bridge_d3_possible(dev)) {
122 : : /*
123 : : * Keep the port resumed 100ms to make sure things like
124 : : * config space accesses from userspace (lspci) will not
125 : : * cause the port to repeatedly suspend and resume.
126 : : */
127 : 0 : pm_runtime_set_autosuspend_delay(&dev->dev, 100);
128 : 0 : pm_runtime_use_autosuspend(&dev->dev);
129 : 0 : pm_runtime_mark_last_busy(&dev->dev);
130 : 0 : pm_runtime_put_autosuspend(&dev->dev);
131 : 0 : pm_runtime_allow(&dev->dev);
132 : : }
133 : :
134 : : return 0;
135 : : }
136 : :
137 : 0 : static void pcie_portdrv_remove(struct pci_dev *dev)
138 : : {
139 [ # # ]: 0 : if (pci_bridge_d3_possible(dev)) {
140 : 0 : pm_runtime_forbid(&dev->dev);
141 : 0 : pm_runtime_get_noresume(&dev->dev);
142 : 0 : pm_runtime_dont_use_autosuspend(&dev->dev);
143 : : }
144 : :
145 : 0 : pcie_port_device_remove(dev);
146 : 0 : }
147 : :
148 : 0 : static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
149 : : enum pci_channel_state error)
150 : : {
151 : : /* Root Port has no impact. Always recovers. */
152 : 0 : return PCI_ERS_RESULT_CAN_RECOVER;
153 : : }
154 : :
155 : 0 : static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
156 : : {
157 : 0 : pci_restore_state(dev);
158 : 0 : pci_save_state(dev);
159 : 0 : return PCI_ERS_RESULT_RECOVERED;
160 : : }
161 : :
162 : 0 : static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
163 : : {
164 : 0 : return PCI_ERS_RESULT_RECOVERED;
165 : : }
166 : :
167 : 0 : static int resume_iter(struct device *device, void *data)
168 : : {
169 : 0 : struct pcie_device *pcie_device;
170 : 0 : struct pcie_port_service_driver *driver;
171 : :
172 [ # # # # ]: 0 : if (device->bus == &pcie_port_bus_type && device->driver) {
173 : 0 : driver = to_service_driver(device->driver);
174 [ # # # # ]: 0 : if (driver && driver->error_resume) {
175 : 0 : pcie_device = to_pcie_device(device);
176 : :
177 : : /* Forward error message to service drivers */
178 : 0 : driver->error_resume(pcie_device->port);
179 : : }
180 : : }
181 : :
182 : 0 : return 0;
183 : : }
184 : :
185 : 0 : static void pcie_portdrv_err_resume(struct pci_dev *dev)
186 : : {
187 : 0 : device_for_each_child(&dev->dev, NULL, resume_iter);
188 : 0 : }
189 : :
190 : : /*
191 : : * LINUX Device Driver Model
192 : : */
193 : : static const struct pci_device_id port_pci_ids[] = {
194 : : /* handle any PCI-Express port */
195 : : { PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0) },
196 : : /* subtractive decode PCI-to-PCI bridge, class type is 060401h */
197 : : { PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x01), ~0) },
198 : : { },
199 : : };
200 : :
201 : : static const struct pci_error_handlers pcie_portdrv_err_handler = {
202 : : .error_detected = pcie_portdrv_error_detected,
203 : : .slot_reset = pcie_portdrv_slot_reset,
204 : : .mmio_enabled = pcie_portdrv_mmio_enabled,
205 : : .resume = pcie_portdrv_err_resume,
206 : : };
207 : :
208 : : static struct pci_driver pcie_portdriver = {
209 : : .name = "pcieport",
210 : : .id_table = &port_pci_ids[0],
211 : :
212 : : .probe = pcie_portdrv_probe,
213 : : .remove = pcie_portdrv_remove,
214 : : .shutdown = pcie_portdrv_remove,
215 : :
216 : : .err_handler = &pcie_portdrv_err_handler,
217 : :
218 : : .driver.pm = PCIE_PORTDRV_PM_OPS,
219 : : };
220 : :
221 : 0 : static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d)
222 : : {
223 : 0 : pr_notice("%s detected: will not use MSI for PCIe PME signaling\n",
224 : : d->ident);
225 : 0 : pcie_pme_disable_msi();
226 : 0 : return 0;
227 : : }
228 : :
229 : : static const struct dmi_system_id pcie_portdrv_dmi_table[] __initconst = {
230 : : /*
231 : : * Boxes that should not use MSI for PCIe PME signaling.
232 : : */
233 : : {
234 : : .callback = dmi_pcie_pme_disable_msi,
235 : : .ident = "MSI Wind U-100",
236 : : .matches = {
237 : : DMI_MATCH(DMI_SYS_VENDOR,
238 : : "MICRO-STAR INTERNATIONAL CO., LTD"),
239 : : DMI_MATCH(DMI_PRODUCT_NAME, "U-100"),
240 : : },
241 : : },
242 : : {}
243 : : };
244 : :
245 : 28 : static void __init pcie_init_services(void)
246 : : {
247 : 28 : pcie_aer_init();
248 : 28 : pcie_pme_init();
249 : 28 : pcie_dpc_init();
250 : 28 : pcie_hp_init();
251 : 28 : pcie_bandwidth_notification_init();
252 : 28 : }
253 : :
254 : 28 : static int __init pcie_portdrv_init(void)
255 : : {
256 [ + - ]: 28 : if (pcie_ports_disabled)
257 : : return -EACCES;
258 : :
259 : 28 : pcie_init_services();
260 : 28 : dmi_check_system(pcie_portdrv_dmi_table);
261 : :
262 : 28 : return pci_register_driver(&pcie_portdriver);
263 : : }
264 : : device_initcall(pcie_portdrv_init);
|