This source file includes following definitions.
- merge_result
- report_error_detected
- report_frozen_detected
- report_normal_detected
- report_mmio_enabled
- report_slot_reset
- report_resume
- default_reset_link
- reset_link
- pcie_do_recovery
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/pci.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/aer.h>
18 #include "portdrv.h"
19 #include "../pci.h"
20
21 static pci_ers_result_t merge_result(enum pci_ers_result orig,
22 enum pci_ers_result new)
23 {
24 if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
25 return PCI_ERS_RESULT_NO_AER_DRIVER;
26
27 if (new == PCI_ERS_RESULT_NONE)
28 return orig;
29
30 switch (orig) {
31 case PCI_ERS_RESULT_CAN_RECOVER:
32 case PCI_ERS_RESULT_RECOVERED:
33 orig = new;
34 break;
35 case PCI_ERS_RESULT_DISCONNECT:
36 if (new == PCI_ERS_RESULT_NEED_RESET)
37 orig = PCI_ERS_RESULT_NEED_RESET;
38 break;
39 default:
40 break;
41 }
42
43 return orig;
44 }
45
46 static int report_error_detected(struct pci_dev *dev,
47 enum pci_channel_state state,
48 enum pci_ers_result *result)
49 {
50 pci_ers_result_t vote;
51 const struct pci_error_handlers *err_handler;
52
53 device_lock(&dev->dev);
54 if (!pci_dev_set_io_state(dev, state) ||
55 !dev->driver ||
56 !dev->driver->err_handler ||
57 !dev->driver->err_handler->error_detected) {
58
59
60
61
62
63
64 if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
65 vote = PCI_ERS_RESULT_NO_AER_DRIVER;
66 else
67 vote = PCI_ERS_RESULT_NONE;
68 } else {
69 err_handler = dev->driver->err_handler;
70 vote = err_handler->error_detected(dev, state);
71 }
72 pci_uevent_ers(dev, vote);
73 *result = merge_result(*result, vote);
74 device_unlock(&dev->dev);
75 return 0;
76 }
77
78 static int report_frozen_detected(struct pci_dev *dev, void *data)
79 {
80 return report_error_detected(dev, pci_channel_io_frozen, data);
81 }
82
83 static int report_normal_detected(struct pci_dev *dev, void *data)
84 {
85 return report_error_detected(dev, pci_channel_io_normal, data);
86 }
87
88 static int report_mmio_enabled(struct pci_dev *dev, void *data)
89 {
90 pci_ers_result_t vote, *result = data;
91 const struct pci_error_handlers *err_handler;
92
93 device_lock(&dev->dev);
94 if (!dev->driver ||
95 !dev->driver->err_handler ||
96 !dev->driver->err_handler->mmio_enabled)
97 goto out;
98
99 err_handler = dev->driver->err_handler;
100 vote = err_handler->mmio_enabled(dev);
101 *result = merge_result(*result, vote);
102 out:
103 device_unlock(&dev->dev);
104 return 0;
105 }
106
107 static int report_slot_reset(struct pci_dev *dev, void *data)
108 {
109 pci_ers_result_t vote, *result = data;
110 const struct pci_error_handlers *err_handler;
111
112 device_lock(&dev->dev);
113 if (!dev->driver ||
114 !dev->driver->err_handler ||
115 !dev->driver->err_handler->slot_reset)
116 goto out;
117
118 err_handler = dev->driver->err_handler;
119 vote = err_handler->slot_reset(dev);
120 *result = merge_result(*result, vote);
121 out:
122 device_unlock(&dev->dev);
123 return 0;
124 }
125
126 static int report_resume(struct pci_dev *dev, void *data)
127 {
128 const struct pci_error_handlers *err_handler;
129
130 device_lock(&dev->dev);
131 if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
132 !dev->driver ||
133 !dev->driver->err_handler ||
134 !dev->driver->err_handler->resume)
135 goto out;
136
137 err_handler = dev->driver->err_handler;
138 err_handler->resume(dev);
139 out:
140 pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
141 device_unlock(&dev->dev);
142 return 0;
143 }
144
145
146
147
148
149
150
151
152 static pci_ers_result_t default_reset_link(struct pci_dev *dev)
153 {
154 int rc;
155
156 rc = pci_bus_error_reset(dev);
157 pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
158 return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
159 }
160
161 static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
162 {
163 pci_ers_result_t status;
164 struct pcie_port_service_driver *driver = NULL;
165
166 driver = pcie_port_find_service(dev, service);
167 if (driver && driver->reset_link) {
168 status = driver->reset_link(dev);
169 } else if (pcie_downstream_port(dev)) {
170 status = default_reset_link(dev);
171 } else {
172 pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
173 pci_name(dev));
174 return PCI_ERS_RESULT_DISCONNECT;
175 }
176
177 if (status != PCI_ERS_RESULT_RECOVERED) {
178 pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n",
179 pci_name(dev));
180 return PCI_ERS_RESULT_DISCONNECT;
181 }
182
183 return status;
184 }
185
186 void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
187 u32 service)
188 {
189 pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
190 struct pci_bus *bus;
191
192
193
194
195
196 if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
197 pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
198 dev = dev->bus->self;
199 bus = dev->subordinate;
200
201 pci_dbg(dev, "broadcast error_detected message\n");
202 if (state == pci_channel_io_frozen)
203 pci_walk_bus(bus, report_frozen_detected, &status);
204 else
205 pci_walk_bus(bus, report_normal_detected, &status);
206
207 if (state == pci_channel_io_frozen &&
208 reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED)
209 goto failed;
210
211 if (status == PCI_ERS_RESULT_CAN_RECOVER) {
212 status = PCI_ERS_RESULT_RECOVERED;
213 pci_dbg(dev, "broadcast mmio_enabled message\n");
214 pci_walk_bus(bus, report_mmio_enabled, &status);
215 }
216
217 if (status == PCI_ERS_RESULT_NEED_RESET) {
218
219
220
221
222
223 status = PCI_ERS_RESULT_RECOVERED;
224 pci_dbg(dev, "broadcast slot_reset message\n");
225 pci_walk_bus(bus, report_slot_reset, &status);
226 }
227
228 if (status != PCI_ERS_RESULT_RECOVERED)
229 goto failed;
230
231 pci_dbg(dev, "broadcast resume message\n");
232 pci_walk_bus(bus, report_resume, &status);
233
234 pci_aer_clear_device_status(dev);
235 pci_cleanup_aer_uncorrect_error_status(dev);
236 pci_info(dev, "AER: Device recovery successful\n");
237 return;
238
239 failed:
240 pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
241
242
243 pci_info(dev, "AER: Device recovery failed\n");
244 }