1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/pci.h>
20#include <linux/sched.h>
21#include <linux/kernel.h>
22#include <linux/errno.h>
23#include <linux/pm.h>
24#include <linux/init.h>
25#include <linux/interrupt.h>
26#include <linux/delay.h>
27#include <linux/pcieport_if.h>
28
29#include "aerdrv.h"
30#include "../../pci.h"
31
32
33
34
35#define DRIVER_VERSION "v1.0"
36#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
37#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
38MODULE_AUTHOR(DRIVER_AUTHOR);
39MODULE_DESCRIPTION(DRIVER_DESC);
40MODULE_LICENSE("GPL");
41
42static int __devinit aer_probe(struct pcie_device *dev);
43static void aer_remove(struct pcie_device *dev);
44static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
45 enum pci_channel_state error);
46static void aer_error_resume(struct pci_dev *dev);
47static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
48
49static struct pci_error_handlers aer_error_handlers = {
50 .error_detected = aer_error_detected,
51 .resume = aer_error_resume,
52};
53
54static struct pcie_port_service_driver aerdriver = {
55 .name = "aer",
56 .port_type = PCIE_RC_PORT,
57 .service = PCIE_PORT_SERVICE_AER,
58
59 .probe = aer_probe,
60 .remove = aer_remove,
61
62 .err_handler = &aer_error_handlers,
63
64 .reset_link = aer_root_reset,
65};
66
67static int pcie_aer_disable;
68
69void pci_no_aer(void)
70{
71 pcie_aer_disable = 1;
72}
73
74
75
76
77
78
79
80
81irqreturn_t aer_irq(int irq, void *context)
82{
83 unsigned int status, id;
84 struct pcie_device *pdev = (struct pcie_device *)context;
85 struct aer_rpc *rpc = get_service_data(pdev);
86 int next_prod_idx;
87 unsigned long flags;
88 int pos;
89
90 pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
91
92
93
94
95 spin_lock_irqsave(&rpc->e_lock, flags);
96
97
98 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
99 if (!(status & ROOT_ERR_STATUS_MASKS)) {
100 spin_unlock_irqrestore(&rpc->e_lock, flags);
101 return IRQ_NONE;
102 }
103
104
105 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
106 pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
107
108
109 next_prod_idx = rpc->prod_idx + 1;
110 if (next_prod_idx == AER_ERROR_SOURCES_MAX)
111 next_prod_idx = 0;
112 if (next_prod_idx == rpc->cons_idx) {
113
114
115
116
117 spin_unlock_irqrestore(&rpc->e_lock, flags);
118 return IRQ_HANDLED;
119 }
120 rpc->e_sources[rpc->prod_idx].status = status;
121 rpc->e_sources[rpc->prod_idx].id = id;
122 rpc->prod_idx = next_prod_idx;
123 spin_unlock_irqrestore(&rpc->e_lock, flags);
124
125
126 schedule_work(&rpc->dpc_handler);
127
128 return IRQ_HANDLED;
129}
130EXPORT_SYMBOL_GPL(aer_irq);
131
132
133
134
135
136
137
138static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
139{
140 struct aer_rpc *rpc;
141
142 rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
143 if (!rpc)
144 return NULL;
145
146
147
148
149
150 spin_lock_init(&rpc->e_lock);
151
152 rpc->rpd = dev;
153 INIT_WORK(&rpc->dpc_handler, aer_isr);
154 rpc->prod_idx = rpc->cons_idx = 0;
155 mutex_init(&rpc->rpc_mutex);
156 init_waitqueue_head(&rpc->wait_release);
157
158
159 set_service_data(dev, rpc);
160
161 return rpc;
162}
163
164
165
166
167
168
169
170static void aer_remove(struct pcie_device *dev)
171{
172 struct aer_rpc *rpc = get_service_data(dev);
173
174 if (rpc) {
175
176 if (rpc->isr)
177 free_irq(dev->irq, dev);
178
179 wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
180
181 aer_delete_rootport(rpc);
182 set_service_data(dev, NULL);
183 }
184}
185
186
187
188
189
190
191
192
193static int __devinit aer_probe(struct pcie_device *dev)
194{
195 int status;
196 struct aer_rpc *rpc;
197 struct device *device = &dev->device;
198
199
200 status = aer_init(dev);
201 if (status)
202 return status;
203
204
205 rpc = aer_alloc_rpc(dev);
206 if (!rpc) {
207 dev_printk(KERN_DEBUG, device, "alloc rpc failed\n");
208 aer_remove(dev);
209 return -ENOMEM;
210 }
211
212
213 status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
214 if (status) {
215 dev_printk(KERN_DEBUG, device, "request IRQ failed\n");
216 aer_remove(dev);
217 return status;
218 }
219
220 rpc->isr = 1;
221
222 aer_enable_rootport(rpc);
223
224 return status;
225}
226
227
228
229
230
231
232
233static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
234{
235 u16 p2p_ctrl;
236 u32 status;
237 int pos;
238
239 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
240
241
242 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
243
244
245 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
246 p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
247 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
248
249
250 p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
251 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
252
253
254
255
256
257
258 msleep(200);
259 dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
260
261
262 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
263 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
264 pci_write_config_dword(dev,
265 pos + PCI_ERR_ROOT_COMMAND,
266 ROOT_PORT_INTR_ON_MESG_MASK);
267
268 return PCI_ERS_RESULT_RECOVERED;
269}
270
271
272
273
274
275
276
277
278static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
279 enum pci_channel_state error)
280{
281
282 return PCI_ERS_RESULT_CAN_RECOVER;
283}
284
285
286
287
288
289
290
291static void aer_error_resume(struct pci_dev *dev)
292{
293 int pos;
294 u32 status, mask;
295 u16 reg16;
296
297
298 pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
299 pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16);
300 pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
301
302
303 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
304 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
305 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
306 if (dev->error_state == pci_channel_io_normal)
307 status &= ~mask;
308 else
309 status &= mask;
310 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
311}
312
313
314
315
316
317
318static int __init aer_service_init(void)
319{
320 if (pcie_aer_disable)
321 return -ENXIO;
322 if (!pci_msi_enabled())
323 return -ENXIO;
324 return pcie_port_service_register(&aerdriver);
325}
326
327
328
329
330
331
332static void __exit aer_service_exit(void)
333{
334 pcie_port_service_unregister(&aerdriver);
335}
336
337module_init(aer_service_init);
338module_exit(aer_service_exit);
339