1 // SPDX-License-Identifier: GPL-2.0
3 * drivers/pci/pcie/aer/aerdrv.c
5 * This file implements the AER root port service driver. The driver will
6 * register an irq handler. When root port triggers an AER interrupt, the irq
7 * handler will collect root port status and schedule a work.
9 * Copyright (C) 2006 Intel Corp.
10 * Tom Long Nguyen (tom.l.nguyen@intel.com)
11 * Zhang Yanmin (yanmin.zhang@intel.com)
15 #include <linux/pci.h>
16 #include <linux/pci-acpi.h>
17 #include <linux/sched.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
21 #include <linux/init.h>
22 #include <linux/interrupt.h>
23 #include <linux/delay.h>
24 #include <linux/pcieport_if.h>
25 #include <linux/slab.h>
28 #include "../../pci.h"
30 static int aer_probe(struct pcie_device
*dev
);
31 static void aer_remove(struct pcie_device
*dev
);
32 static void aer_error_resume(struct pci_dev
*dev
);
33 static pci_ers_result_t
aer_root_reset(struct pci_dev
*dev
);
35 static struct pcie_port_service_driver aerdriver
= {
37 .port_type
= PCI_EXP_TYPE_ROOT_PORT
,
38 .service
= PCIE_PORT_SERVICE_AER
,
42 .error_resume
= aer_error_resume
,
43 .reset_link
= aer_root_reset
,
46 static int pcie_aer_disable
;
53 bool pci_aer_available(void)
55 return !pcie_aer_disable
&& pci_msi_enabled();
58 static int set_device_error_reporting(struct pci_dev
*dev
, void *data
)
60 bool enable
= *((bool *)data
);
61 int type
= pci_pcie_type(dev
);
63 if ((type
== PCI_EXP_TYPE_ROOT_PORT
) ||
64 (type
== PCI_EXP_TYPE_UPSTREAM
) ||
65 (type
== PCI_EXP_TYPE_DOWNSTREAM
)) {
67 pci_enable_pcie_error_reporting(dev
);
69 pci_disable_pcie_error_reporting(dev
);
73 pcie_set_ecrc_checking(dev
);
79 * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports.
80 * @dev: pointer to root port's pci_dev data structure
81 * @enable: true = enable error reporting, false = disable error reporting.
83 static void set_downstream_devices_error_reporting(struct pci_dev
*dev
,
86 set_device_error_reporting(dev
, &enable
);
88 if (!dev
->subordinate
)
90 pci_walk_bus(dev
->subordinate
, set_device_error_reporting
, &enable
);
94 * aer_enable_rootport - enable Root Port's interrupts when receiving messages
95 * @rpc: pointer to a Root Port data structure
97 * Invoked when PCIe bus loads AER service driver.
99 static void aer_enable_rootport(struct aer_rpc
*rpc
)
101 struct pci_dev
*pdev
= rpc
->rpd
->port
;
106 /* Clear PCIe Capability's Device Status */
107 pcie_capability_read_word(pdev
, PCI_EXP_DEVSTA
, ®16
);
108 pcie_capability_write_word(pdev
, PCI_EXP_DEVSTA
, reg16
);
110 /* Disable system error generation in response to error messages */
111 pcie_capability_clear_word(pdev
, PCI_EXP_RTCTL
,
112 SYSTEM_ERROR_INTR_ON_MESG_MASK
);
114 aer_pos
= pdev
->aer_cap
;
115 /* Clear error status */
116 pci_read_config_dword(pdev
, aer_pos
+ PCI_ERR_ROOT_STATUS
, ®32
);
117 pci_write_config_dword(pdev
, aer_pos
+ PCI_ERR_ROOT_STATUS
, reg32
);
118 pci_read_config_dword(pdev
, aer_pos
+ PCI_ERR_COR_STATUS
, ®32
);
119 pci_write_config_dword(pdev
, aer_pos
+ PCI_ERR_COR_STATUS
, reg32
);
120 pci_read_config_dword(pdev
, aer_pos
+ PCI_ERR_UNCOR_STATUS
, ®32
);
121 pci_write_config_dword(pdev
, aer_pos
+ PCI_ERR_UNCOR_STATUS
, reg32
);
124 * Enable error reporting for the root port device and downstream port
127 set_downstream_devices_error_reporting(pdev
, true);
129 /* Enable Root Port's interrupt in response to error messages */
130 pci_read_config_dword(pdev
, aer_pos
+ PCI_ERR_ROOT_COMMAND
, ®32
);
131 reg32
|= ROOT_PORT_INTR_ON_MESG_MASK
;
132 pci_write_config_dword(pdev
, aer_pos
+ PCI_ERR_ROOT_COMMAND
, reg32
);
136 * aer_disable_rootport - disable Root Port's interrupts when receiving messages
137 * @rpc: pointer to a Root Port data structure
139 * Invoked when PCIe bus unloads AER service driver.
141 static void aer_disable_rootport(struct aer_rpc
*rpc
)
143 struct pci_dev
*pdev
= rpc
->rpd
->port
;
148 * Disable error reporting for the root port device and downstream port
151 set_downstream_devices_error_reporting(pdev
, false);
154 /* Disable Root's interrupt in response to error messages */
155 pci_read_config_dword(pdev
, pos
+ PCI_ERR_ROOT_COMMAND
, ®32
);
156 reg32
&= ~ROOT_PORT_INTR_ON_MESG_MASK
;
157 pci_write_config_dword(pdev
, pos
+ PCI_ERR_ROOT_COMMAND
, reg32
);
159 /* Clear Root's error status reg */
160 pci_read_config_dword(pdev
, pos
+ PCI_ERR_ROOT_STATUS
, ®32
);
161 pci_write_config_dword(pdev
, pos
+ PCI_ERR_ROOT_STATUS
, reg32
);
165 * aer_irq - Root Port's ISR
166 * @irq: IRQ assigned to Root Port
167 * @context: pointer to Root Port data structure
169 * Invoked when Root Port detects AER messages.
171 irqreturn_t
aer_irq(int irq
, void *context
)
173 unsigned int status
, id
;
174 struct pcie_device
*pdev
= (struct pcie_device
*)context
;
175 struct aer_rpc
*rpc
= get_service_data(pdev
);
180 pos
= pdev
->port
->aer_cap
;
182 * Must lock access to Root Error Status Reg, Root Error ID Reg,
183 * and Root error producer/consumer index
185 spin_lock_irqsave(&rpc
->e_lock
, flags
);
187 /* Read error status */
188 pci_read_config_dword(pdev
->port
, pos
+ PCI_ERR_ROOT_STATUS
, &status
);
189 if (!(status
& (PCI_ERR_ROOT_UNCOR_RCV
|PCI_ERR_ROOT_COR_RCV
))) {
190 spin_unlock_irqrestore(&rpc
->e_lock
, flags
);
194 /* Read error source and clear error status */
195 pci_read_config_dword(pdev
->port
, pos
+ PCI_ERR_ROOT_ERR_SRC
, &id
);
196 pci_write_config_dword(pdev
->port
, pos
+ PCI_ERR_ROOT_STATUS
, status
);
198 /* Store error source for later DPC handler */
199 next_prod_idx
= rpc
->prod_idx
+ 1;
200 if (next_prod_idx
== AER_ERROR_SOURCES_MAX
)
202 if (next_prod_idx
== rpc
->cons_idx
) {
204 * Error Storm Condition - possibly the same error occurred.
207 spin_unlock_irqrestore(&rpc
->e_lock
, flags
);
210 rpc
->e_sources
[rpc
->prod_idx
].status
= status
;
211 rpc
->e_sources
[rpc
->prod_idx
].id
= id
;
212 rpc
->prod_idx
= next_prod_idx
;
213 spin_unlock_irqrestore(&rpc
->e_lock
, flags
);
215 /* Invoke DPC handler */
216 schedule_work(&rpc
->dpc_handler
);
220 EXPORT_SYMBOL_GPL(aer_irq
);
223 * aer_alloc_rpc - allocate Root Port data structure
224 * @dev: pointer to the pcie_dev data structure
226 * Invoked when Root Port's AER service is loaded.
228 static struct aer_rpc
*aer_alloc_rpc(struct pcie_device
*dev
)
232 rpc
= kzalloc(sizeof(struct aer_rpc
), GFP_KERNEL
);
236 /* Initialize Root lock access, e_lock, to Root Error Status Reg */
237 spin_lock_init(&rpc
->e_lock
);
240 INIT_WORK(&rpc
->dpc_handler
, aer_isr
);
241 mutex_init(&rpc
->rpc_mutex
);
243 /* Use PCIe bus function to store rpc into PCIe device */
244 set_service_data(dev
, rpc
);
250 * aer_remove - clean up resources
251 * @dev: pointer to the pcie_dev data structure
253 * Invoked when PCI Express bus unloads or AER probe fails.
255 static void aer_remove(struct pcie_device
*dev
)
257 struct aer_rpc
*rpc
= get_service_data(dev
);
260 /* If register interrupt service, it must be free. */
262 free_irq(dev
->irq
, dev
);
264 flush_work(&rpc
->dpc_handler
);
265 aer_disable_rootport(rpc
);
267 set_service_data(dev
, NULL
);
272 * aer_probe - initialize resources
273 * @dev: pointer to the pcie_dev data structure
275 * Invoked when PCI Express bus loads AER service driver.
277 static int aer_probe(struct pcie_device
*dev
)
281 struct device
*device
= &dev
->port
->dev
;
283 /* Alloc rpc data structure */
284 rpc
= aer_alloc_rpc(dev
);
286 dev_printk(KERN_DEBUG
, device
, "alloc AER rpc failed\n");
291 /* Request IRQ ISR */
292 status
= request_irq(dev
->irq
, aer_irq
, IRQF_SHARED
, "aerdrv", dev
);
294 dev_printk(KERN_DEBUG
, device
, "request AER IRQ %d failed\n",
302 aer_enable_rootport(rpc
);
303 dev_info(device
, "AER enabled with IRQ %d\n", dev
->irq
);
308 * aer_root_reset - reset link on Root Port
309 * @dev: pointer to Root Port's pci_dev data structure
311 * Invoked by Port Bus driver when performing link reset at Root Port.
313 static pci_ers_result_t
aer_root_reset(struct pci_dev
*dev
)
320 /* Disable Root's interrupt in response to error messages */
321 pci_read_config_dword(dev
, pos
+ PCI_ERR_ROOT_COMMAND
, ®32
);
322 reg32
&= ~ROOT_PORT_INTR_ON_MESG_MASK
;
323 pci_write_config_dword(dev
, pos
+ PCI_ERR_ROOT_COMMAND
, reg32
);
325 pci_reset_bridge_secondary_bus(dev
);
326 pci_printk(KERN_DEBUG
, dev
, "Root Port link has been reset\n");
328 /* Clear Root Error Status */
329 pci_read_config_dword(dev
, pos
+ PCI_ERR_ROOT_STATUS
, ®32
);
330 pci_write_config_dword(dev
, pos
+ PCI_ERR_ROOT_STATUS
, reg32
);
332 /* Enable Root Port's interrupt in response to error messages */
333 pci_read_config_dword(dev
, pos
+ PCI_ERR_ROOT_COMMAND
, ®32
);
334 reg32
|= ROOT_PORT_INTR_ON_MESG_MASK
;
335 pci_write_config_dword(dev
, pos
+ PCI_ERR_ROOT_COMMAND
, reg32
);
337 return PCI_ERS_RESULT_RECOVERED
;
341 * aer_error_resume - clean up corresponding error status bits
342 * @dev: pointer to Root Port's pci_dev data structure
344 * Invoked by Port Bus driver during nonfatal recovery.
346 static void aer_error_resume(struct pci_dev
*dev
)
352 /* Clean up Root device status */
353 pcie_capability_read_word(dev
, PCI_EXP_DEVSTA
, ®16
);
354 pcie_capability_write_word(dev
, PCI_EXP_DEVSTA
, reg16
);
356 /* Clean AER Root Error Status */
358 pci_read_config_dword(dev
, pos
+ PCI_ERR_UNCOR_STATUS
, &status
);
359 pci_read_config_dword(dev
, pos
+ PCI_ERR_UNCOR_SEVER
, &mask
);
360 if (dev
->error_state
== pci_channel_io_normal
)
361 status
&= ~mask
; /* Clear corresponding nonfatal bits */
363 status
&= mask
; /* Clear corresponding fatal bits */
364 pci_write_config_dword(dev
, pos
+ PCI_ERR_UNCOR_STATUS
, status
);
368 * aer_service_init - register AER root service driver
370 * Invoked when AER root service driver is loaded.
372 static int __init
aer_service_init(void)
374 if (!pci_aer_available() || aer_acpi_firmware_first())
376 return pcie_port_service_register(&aerdriver
);
378 device_initcall(aer_service_init
);