]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/pci/pcie/aer/aerdrv.c
Merge branch 'pci/host/qcom'
[linux.git] / drivers / pci / pcie / aer / aerdrv.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Implement the AER root port service driver. The driver registers an IRQ
4  * handler. When a root port triggers an AER interrupt, the IRQ handler
5  * collects root port status and schedules work.
6  *
7  * Copyright (C) 2006 Intel Corp.
8  *      Tom Long Nguyen (tom.l.nguyen@intel.com)
9  *      Zhang Yanmin (yanmin.zhang@intel.com)
10  */
11
12 #include <linux/pci.h>
13 #include <linux/pci-acpi.h>
14 #include <linux/sched.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/pm.h>
18 #include <linux/init.h>
19 #include <linux/interrupt.h>
20 #include <linux/delay.h>
21 #include <linux/slab.h>
22
23 #include "aerdrv.h"
24 #include "../../pci.h"
25
26 static int aer_probe(struct pcie_device *dev);
27 static void aer_remove(struct pcie_device *dev);
28 static void aer_error_resume(struct pci_dev *dev);
29 static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
30
31 static struct pcie_port_service_driver aerdriver = {
32         .name           = "aer",
33         .port_type      = PCI_EXP_TYPE_ROOT_PORT,
34         .service        = PCIE_PORT_SERVICE_AER,
35
36         .probe          = aer_probe,
37         .remove         = aer_remove,
38         .error_resume   = aer_error_resume,
39         .reset_link     = aer_root_reset,
40 };
41
42 static int pcie_aer_disable;
43
44 void pci_no_aer(void)
45 {
46         pcie_aer_disable = 1;
47 }
48
49 bool pci_aer_available(void)
50 {
51         return !pcie_aer_disable && pci_msi_enabled();
52 }
53
54 static int set_device_error_reporting(struct pci_dev *dev, void *data)
55 {
56         bool enable = *((bool *)data);
57         int type = pci_pcie_type(dev);
58
59         if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
60             (type == PCI_EXP_TYPE_UPSTREAM) ||
61             (type == PCI_EXP_TYPE_DOWNSTREAM)) {
62                 if (enable)
63                         pci_enable_pcie_error_reporting(dev);
64                 else
65                         pci_disable_pcie_error_reporting(dev);
66         }
67
68         if (enable)
69                 pcie_set_ecrc_checking(dev);
70
71         return 0;
72 }
73
74 /**
75  * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
76  * @dev: pointer to root port's pci_dev data structure
77  * @enable: true = enable error reporting, false = disable error reporting.
78  */
79 static void set_downstream_devices_error_reporting(struct pci_dev *dev,
80                                                    bool enable)
81 {
82         set_device_error_reporting(dev, &enable);
83
84         if (!dev->subordinate)
85                 return;
86         pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
87 }
88
89 /**
90  * aer_enable_rootport - enable Root Port's interrupts when receiving messages
91  * @rpc: pointer to a Root Port data structure
92  *
93  * Invoked when PCIe bus loads AER service driver.
94  */
95 static void aer_enable_rootport(struct aer_rpc *rpc)
96 {
97         struct pci_dev *pdev = rpc->rpd;
98         int aer_pos;
99         u16 reg16;
100         u32 reg32;
101
102         /* Clear PCIe Capability's Device Status */
103         pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, &reg16);
104         pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16);
105
106         /* Disable system error generation in response to error messages */
107         pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
108                                    SYSTEM_ERROR_INTR_ON_MESG_MASK);
109
110         aer_pos = pdev->aer_cap;
111         /* Clear error status */
112         pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
113         pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
114         pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
115         pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
116         pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
117         pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
118
119         /*
120          * Enable error reporting for the root port device and downstream port
121          * devices.
122          */
123         set_downstream_devices_error_reporting(pdev, true);
124
125         /* Enable Root Port's interrupt in response to error messages */
126         pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, &reg32);
127         reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
128         pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32);
129 }
130
131 /**
132  * aer_disable_rootport - disable Root Port's interrupts when receiving messages
133  * @rpc: pointer to a Root Port data structure
134  *
135  * Invoked when PCIe bus unloads AER service driver.
136  */
137 static void aer_disable_rootport(struct aer_rpc *rpc)
138 {
139         struct pci_dev *pdev = rpc->rpd;
140         u32 reg32;
141         int pos;
142
143         /*
144          * Disable error reporting for the root port device and downstream port
145          * devices.
146          */
147         set_downstream_devices_error_reporting(pdev, false);
148
149         pos = pdev->aer_cap;
150         /* Disable Root's interrupt in response to error messages */
151         pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
152         reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
153         pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32);
154
155         /* Clear Root's error status reg */
156         pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
157         pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
158 }
159
160 /**
161  * aer_irq - Root Port's ISR
162  * @irq: IRQ assigned to Root Port
163  * @context: pointer to Root Port data structure
164  *
165  * Invoked when Root Port detects AER messages.
166  */
167 irqreturn_t aer_irq(int irq, void *context)
168 {
169         unsigned int status, id;
170         struct pcie_device *pdev = (struct pcie_device *)context;
171         struct aer_rpc *rpc = get_service_data(pdev);
172         int next_prod_idx;
173         unsigned long flags;
174         int pos;
175
176         pos = pdev->port->aer_cap;
177         /*
178          * Must lock access to Root Error Status Reg, Root Error ID Reg,
179          * and Root error producer/consumer index
180          */
181         spin_lock_irqsave(&rpc->e_lock, flags);
182
183         /* Read error status */
184         pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
185         if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
186                 spin_unlock_irqrestore(&rpc->e_lock, flags);
187                 return IRQ_NONE;
188         }
189
190         /* Read error source and clear error status */
191         pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
192         pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
193
194         /* Store error source for later DPC handler */
195         next_prod_idx = rpc->prod_idx + 1;
196         if (next_prod_idx == AER_ERROR_SOURCES_MAX)
197                 next_prod_idx = 0;
198         if (next_prod_idx == rpc->cons_idx) {
199                 /*
200                  * Error Storm Condition - possibly the same error occurred.
201                  * Drop the error.
202                  */
203                 spin_unlock_irqrestore(&rpc->e_lock, flags);
204                 return IRQ_HANDLED;
205         }
206         rpc->e_sources[rpc->prod_idx].status =  status;
207         rpc->e_sources[rpc->prod_idx].id = id;
208         rpc->prod_idx = next_prod_idx;
209         spin_unlock_irqrestore(&rpc->e_lock, flags);
210
211         /*  Invoke DPC handler */
212         schedule_work(&rpc->dpc_handler);
213
214         return IRQ_HANDLED;
215 }
216 EXPORT_SYMBOL_GPL(aer_irq);
217
218 /**
219  * aer_alloc_rpc - allocate Root Port data structure
220  * @dev: pointer to the pcie_dev data structure
221  *
222  * Invoked when Root Port's AER service is loaded.
223  */
224 static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
225 {
226         struct aer_rpc *rpc;
227
228         rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
229         if (!rpc)
230                 return NULL;
231
232         /* Initialize Root lock access, e_lock, to Root Error Status Reg */
233         spin_lock_init(&rpc->e_lock);
234
235         rpc->rpd = dev->port;
236         INIT_WORK(&rpc->dpc_handler, aer_isr);
237         mutex_init(&rpc->rpc_mutex);
238
239         /* Use PCIe bus function to store rpc into PCIe device */
240         set_service_data(dev, rpc);
241
242         return rpc;
243 }
244
245 /**
246  * aer_remove - clean up resources
247  * @dev: pointer to the pcie_dev data structure
248  *
249  * Invoked when PCI Express bus unloads or AER probe fails.
250  */
251 static void aer_remove(struct pcie_device *dev)
252 {
253         struct aer_rpc *rpc = get_service_data(dev);
254
255         if (rpc) {
256                 /* If register interrupt service, it must be free. */
257                 if (rpc->isr)
258                         free_irq(dev->irq, dev);
259
260                 flush_work(&rpc->dpc_handler);
261                 aer_disable_rootport(rpc);
262                 kfree(rpc);
263                 set_service_data(dev, NULL);
264         }
265 }
266
267 /**
268  * aer_probe - initialize resources
269  * @dev: pointer to the pcie_dev data structure
270  *
271  * Invoked when PCI Express bus loads AER service driver.
272  */
273 static int aer_probe(struct pcie_device *dev)
274 {
275         int status;
276         struct aer_rpc *rpc;
277         struct device *device = &dev->port->dev;
278
279         /* Alloc rpc data structure */
280         rpc = aer_alloc_rpc(dev);
281         if (!rpc) {
282                 dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n");
283                 aer_remove(dev);
284                 return -ENOMEM;
285         }
286
287         /* Request IRQ ISR */
288         status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
289         if (status) {
290                 dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n",
291                            dev->irq);
292                 aer_remove(dev);
293                 return status;
294         }
295
296         rpc->isr = 1;
297
298         aer_enable_rootport(rpc);
299         dev_info(device, "AER enabled with IRQ %d\n", dev->irq);
300         return 0;
301 }
302
303 /**
304  * aer_root_reset - reset link on Root Port
305  * @dev: pointer to Root Port's pci_dev data structure
306  *
307  * Invoked by Port Bus driver when performing link reset at Root Port.
308  */
309 static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
310 {
311         u32 reg32;
312         int pos;
313
314         pos = dev->aer_cap;
315
316         /* Disable Root's interrupt in response to error messages */
317         pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
318         reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
319         pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
320
321         pci_reset_bridge_secondary_bus(dev);
322         pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n");
323
324         /* Clear Root Error Status */
325         pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
326         pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
327
328         /* Enable Root Port's interrupt in response to error messages */
329         pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
330         reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
331         pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
332
333         return PCI_ERS_RESULT_RECOVERED;
334 }
335
336 /**
337  * aer_error_resume - clean up corresponding error status bits
338  * @dev: pointer to Root Port's pci_dev data structure
339  *
340  * Invoked by Port Bus driver during nonfatal recovery.
341  */
342 static void aer_error_resume(struct pci_dev *dev)
343 {
344         int pos;
345         u32 status, mask;
346         u16 reg16;
347
348         /* Clean up Root device status */
349         pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &reg16);
350         pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16);
351
352         /* Clean AER Root Error Status */
353         pos = dev->aer_cap;
354         pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
355         pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
356         status &= ~mask; /* Clear corresponding nonfatal bits */
357         pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
358 }
359
360 /**
361  * aer_service_init - register AER root service driver
362  *
363  * Invoked when AER root service driver is loaded.
364  */
365 static int __init aer_service_init(void)
366 {
367         if (!pci_aer_available() || aer_acpi_firmware_first())
368                 return -ENXIO;
369         return pcie_port_service_register(&aerdriver);
370 }
371 device_initcall(aer_service_init);