blob: 8d3bc28821ba82b98107f19de6fe32901ae5a70c [file] [log] [blame]
Bjorn Helgaase1e86ee2018-01-26 14:12:23 -06001// SPDX-License-Identifier: GPL-2.0
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +08002/*
Bjorn Helgaasdf62ab52018-03-09 16:36:33 -06003 * 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.
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +08006 *
7 * Copyright (C) 2006 Intel Corp.
8 * Tom Long Nguyen (tom.l.nguyen@intel.com)
9 * Zhang Yanmin (yanmin.zhang@intel.com)
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +080010 */
11
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +080012#include <linux/pci.h>
Rafael J. Wysocki415e12b2011-01-07 00:55:09 +010013#include <linux/pci-acpi.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040014#include <linux/sched.h>
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +080015#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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +080022
23#include "aerdrv.h"
Alex Chiang5d9526d2008-06-04 11:39:07 -060024#include "../../pci.h"
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +080025
Randy Dunlap7f785762007-10-05 13:17:58 -070026static int pcie_aer_disable;
27
28void pci_no_aer(void)
29{
Bjorn Helgaas7ece1412016-09-06 16:24:37 -050030 pcie_aer_disable = 1;
Randy Dunlap7f785762007-10-05 13:17:58 -070031}
32
Rafael J. Wysockif1a7bfa2010-08-21 01:50:52 +020033bool pci_aer_available(void)
34{
35 return !pcie_aer_disable && pci_msi_enabled();
36}
37
Bjorn Helgaas3c43a642018-06-08 08:31:57 -050038/**
39 * aer_irq - Root Port's ISR
40 * @irq: IRQ assigned to Root Port
41 * @context: pointer to Root Port data structure
42 *
43 * Invoked when Root Port detects AER messages.
44 */
45irqreturn_t aer_irq(int irq, void *context)
46{
47 unsigned int status, id;
48 struct pcie_device *pdev = (struct pcie_device *)context;
49 struct aer_rpc *rpc = get_service_data(pdev);
50 int next_prod_idx;
51 unsigned long flags;
52 int pos;
53
54 pos = pdev->port->aer_cap;
55 /*
56 * Must lock access to Root Error Status Reg, Root Error ID Reg,
57 * and Root error producer/consumer index
58 */
59 spin_lock_irqsave(&rpc->e_lock, flags);
60
61 /* Read error status */
62 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
63 if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
64 spin_unlock_irqrestore(&rpc->e_lock, flags);
65 return IRQ_NONE;
66 }
67
68 /* Read error source and clear error status */
69 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
70 pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
71
72 /* Store error source for later DPC handler */
73 next_prod_idx = rpc->prod_idx + 1;
74 if (next_prod_idx == AER_ERROR_SOURCES_MAX)
75 next_prod_idx = 0;
76 if (next_prod_idx == rpc->cons_idx) {
77 /*
78 * Error Storm Condition - possibly the same error occurred.
79 * Drop the error.
80 */
81 spin_unlock_irqrestore(&rpc->e_lock, flags);
82 return IRQ_HANDLED;
83 }
84 rpc->e_sources[rpc->prod_idx].status = status;
85 rpc->e_sources[rpc->prod_idx].id = id;
86 rpc->prod_idx = next_prod_idx;
87 spin_unlock_irqrestore(&rpc->e_lock, flags);
88
89 /* Invoke DPC handler */
90 schedule_work(&rpc->dpc_handler);
91
92 return IRQ_HANDLED;
93}
94EXPORT_SYMBOL_GPL(aer_irq);
95
Hidetoshi Seto843f4692010-04-15 13:10:53 +090096static int set_device_error_reporting(struct pci_dev *dev, void *data)
97{
98 bool enable = *((bool *)data);
Yijing Wang62f87c02012-07-24 17:20:03 +080099 int type = pci_pcie_type(dev);
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900100
Yijing Wang62f87c02012-07-24 17:20:03 +0800101 if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
102 (type == PCI_EXP_TYPE_UPSTREAM) ||
103 (type == PCI_EXP_TYPE_DOWNSTREAM)) {
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900104 if (enable)
105 pci_enable_pcie_error_reporting(dev);
106 else
107 pci_disable_pcie_error_reporting(dev);
108 }
109
110 if (enable)
111 pcie_set_ecrc_checking(dev);
112
113 return 0;
114}
115
116/**
117 * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports.
118 * @dev: pointer to root port's pci_dev data structure
119 * @enable: true = enable error reporting, false = disable error reporting.
120 */
121static void set_downstream_devices_error_reporting(struct pci_dev *dev,
122 bool enable)
123{
124 set_device_error_reporting(dev, &enable);
125
126 if (!dev->subordinate)
127 return;
128 pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
129}
130
131/**
132 * aer_enable_rootport - enable Root Port's interrupts when receiving messages
133 * @rpc: pointer to a Root Port data structure
134 *
135 * Invoked when PCIe bus loads AER service driver.
136 */
137static void aer_enable_rootport(struct aer_rpc *rpc)
138{
Keith Busche13d17f2018-04-09 16:04:42 -0600139 struct pci_dev *pdev = rpc->rpd;
Jiang Liu43bd4ee2012-07-24 17:20:11 +0800140 int aer_pos;
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900141 u16 reg16;
142 u32 reg32;
143
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900144 /* Clear PCIe Capability's Device Status */
Jiang Liu43bd4ee2012-07-24 17:20:11 +0800145 pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, &reg16);
146 pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16);
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900147
148 /* Disable system error generation in response to error messages */
Jiang Liu43bd4ee2012-07-24 17:20:11 +0800149 pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
150 SYSTEM_ERROR_INTR_ON_MESG_MASK);
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900151
Keith Busch66b80802016-09-27 16:23:34 -0400152 aer_pos = pdev->aer_cap;
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900153 /* Clear error status */
154 pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
155 pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
156 pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
157 pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
158 pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
159 pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
160
161 /*
162 * Enable error reporting for the root port device and downstream port
163 * devices.
164 */
165 set_downstream_devices_error_reporting(pdev, true);
166
167 /* Enable Root Port's interrupt in response to error messages */
168 pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, &reg32);
169 reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
170 pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32);
171}
172
173/**
174 * aer_disable_rootport - disable Root Port's interrupts when receiving messages
175 * @rpc: pointer to a Root Port data structure
176 *
177 * Invoked when PCIe bus unloads AER service driver.
178 */
179static void aer_disable_rootport(struct aer_rpc *rpc)
180{
Keith Busche13d17f2018-04-09 16:04:42 -0600181 struct pci_dev *pdev = rpc->rpd;
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900182 u32 reg32;
183 int pos;
184
185 /*
186 * Disable error reporting for the root port device and downstream port
187 * devices.
188 */
189 set_downstream_devices_error_reporting(pdev, false);
190
Keith Busch66b80802016-09-27 16:23:34 -0400191 pos = pdev->aer_cap;
Hidetoshi Seto843f4692010-04-15 13:10:53 +0900192 /* Disable Root's interrupt in response to error messages */
193 pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
194 reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
195 pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32);
196
197 /* Clear Root's error status reg */
198 pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
199 pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
200}
201
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800202/**
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800203 * aer_alloc_rpc - allocate Root Port data structure
204 * @dev: pointer to the pcie_dev data structure
205 *
206 * Invoked when Root Port's AER service is loaded.
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900207 */
Hidetoshi Setoc9a91882009-09-07 17:07:29 +0900208static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800209{
210 struct aer_rpc *rpc;
211
Hidetoshi Setoc9a91882009-09-07 17:07:29 +0900212 rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
213 if (!rpc)
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800214 return NULL;
215
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900216 /* Initialize Root lock access, e_lock, to Root Error Status Reg */
Milind Arun Choudharyf5609d72007-07-09 11:55:54 -0700217 spin_lock_init(&rpc->e_lock);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800218
Keith Busche13d17f2018-04-09 16:04:42 -0600219 rpc->rpd = dev->port;
David Howells65f27f32006-11-22 14:55:48 +0000220 INIT_WORK(&rpc->dpc_handler, aer_isr);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800221 mutex_init(&rpc->rpc_mutex);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800222
Stefan Assmann45e829e2009-12-03 06:49:24 -0500223 /* Use PCIe bus function to store rpc into PCIe device */
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800224 set_service_data(dev, rpc);
225
226 return rpc;
227}
228
229/**
230 * aer_remove - clean up resources
231 * @dev: pointer to the pcie_dev data structure
232 *
233 * Invoked when PCI Express bus unloads or AER probe fails.
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900234 */
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800235static void aer_remove(struct pcie_device *dev)
236{
237 struct aer_rpc *rpc = get_service_data(dev);
238
239 if (rpc) {
240 /* If register interrupt service, it must be free. */
241 if (rpc->isr)
242 free_irq(dev->irq, dev);
243
Sebastian Andrzej Siewior4ae21822016-01-25 10:08:00 -0600244 flush_work(&rpc->dpc_handler);
Hidetoshi Seto460d2982010-04-15 13:10:03 +0900245 aer_disable_rootport(rpc);
246 kfree(rpc);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800247 set_service_data(dev, NULL);
248 }
249}
250
251/**
252 * aer_probe - initialize resources
253 * @dev: pointer to the pcie_dev data structure
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800254 *
255 * Invoked when PCI Express bus loads AER service driver.
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900256 */
Bill Pemberton15856ad2012-11-21 15:35:00 -0500257static int aer_probe(struct pcie_device *dev)
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800258{
259 int status;
260 struct aer_rpc *rpc;
Bjorn Helgaas576700b2016-11-21 15:24:25 -0600261 struct device *device = &dev->port->dev;
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800262
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800263 /* Alloc rpc data structure */
Hidetoshi Setoc9a91882009-09-07 17:07:29 +0900264 rpc = aer_alloc_rpc(dev);
265 if (!rpc) {
Bjorn Helgaas576700b2016-11-21 15:24:25 -0600266 dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n");
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800267 aer_remove(dev);
268 return -ENOMEM;
269 }
270
271 /* Request IRQ ISR */
Hidetoshi Setoc9a91882009-09-07 17:07:29 +0900272 status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
273 if (status) {
Bjorn Helgaas576700b2016-11-21 15:24:25 -0600274 dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n",
275 dev->irq);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800276 aer_remove(dev);
277 return status;
278 }
279
280 rpc->isr = 1;
281
282 aer_enable_rootport(rpc);
Bjorn Helgaas68a55ae2016-11-21 15:34:02 -0600283 dev_info(device, "AER enabled with IRQ %d\n", dev->irq);
284 return 0;
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800285}
286
287/**
288 * aer_root_reset - reset link on Root Port
289 * @dev: pointer to Root Port's pci_dev data structure
290 *
291 * Invoked by Port Bus driver when performing link reset at Root Port.
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900292 */
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800293static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
294{
Hidetoshi Setoc6d34ed2010-04-15 13:09:13 +0900295 u32 reg32;
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800296 int pos;
297
Keith Busch66b80802016-09-27 16:23:34 -0400298 pos = dev->aer_cap;
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800299
300 /* Disable Root's interrupt in response to error messages */
Hidetoshi Setoc6d34ed2010-04-15 13:09:13 +0900301 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
302 reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
303 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800304
Alex Williamson1b95ce82013-08-08 14:10:20 -0600305 pci_reset_bridge_secondary_bus(dev);
Frederick Lawler7506dc72018-01-18 12:55:24 -0600306 pci_printk(KERN_DEBUG, dev, "Root Port link has been reset\n");
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800307
Hidetoshi Setoc6d34ed2010-04-15 13:09:13 +0900308 /* Clear Root Error Status */
309 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
310 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
311
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800312 /* Enable Root Port's interrupt in response to error messages */
Hidetoshi Setoc6d34ed2010-04-15 13:09:13 +0900313 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
314 reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
315 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800316
317 return PCI_ERS_RESULT_RECOVERED;
318}
319
320/**
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800321 * aer_error_resume - clean up corresponding error status bits
322 * @dev: pointer to Root Port's pci_dev data structure
323 *
324 * Invoked by Port Bus driver during nonfatal recovery.
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900325 */
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800326static void aer_error_resume(struct pci_dev *dev)
327{
328 int pos;
329 u32 status, mask;
330 u16 reg16;
331
332 /* Clean up Root device status */
Jiang Liu43bd4ee2012-07-24 17:20:11 +0800333 pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &reg16);
334 pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800335
336 /* Clean AER Root Error Status */
Keith Busch66b80802016-09-27 16:23:34 -0400337 pos = dev->aer_cap;
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800338 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
339 pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
Oza Pawandeep7e9084b2018-05-17 16:44:13 -0500340 status &= ~mask; /* Clear corresponding nonfatal bits */
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800341 pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
342}
343
Bjorn Helgaas0054ca82018-06-08 08:31:42 -0500344static struct pcie_port_service_driver aerdriver = {
345 .name = "aer",
346 .port_type = PCI_EXP_TYPE_ROOT_PORT,
347 .service = PCIE_PORT_SERVICE_AER,
348
349 .probe = aer_probe,
350 .remove = aer_remove,
351 .error_resume = aer_error_resume,
352 .reset_link = aer_root_reset,
353};
354
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800355/**
356 * aer_service_init - register AER root service driver
357 *
358 * Invoked when AER root service driver is loaded.
Hidetoshi Setof6d37802010-04-15 13:22:11 +0900359 */
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800360static int __init aer_service_init(void)
361{
Rafael J. Wysockib22c3d82010-09-20 18:50:00 +0200362 if (!pci_aer_available() || aer_acpi_firmware_first())
Andi Kleen3e77a3f2009-09-16 22:40:22 +0200363 return -ENXIO;
Sam Ravnborgc1996c22007-02-27 10:22:00 +0100364 return pcie_port_service_register(&aerdriver);
Zhang, Yanmin6c2b3742006-07-31 15:21:33 +0800365}
Paul Gortmaker87563362016-08-24 16:57:46 -0400366device_initcall(aer_service_init);