]> Git Repo - linux.git/blame - drivers/pci/pcie/err.c
Merge tag 'libnvdimm-fixes-4.20-rc3' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / pci / pcie / err.c
CommitLineData
2e28bc84
OP
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * This file implements the error recovery as a core part of PCIe error
4 * reporting. When a PCIe error is delivered, an error message will be
5 * collected and printed to console, then, an error recovery procedure
6 * will be executed by following the PCI error recovery rules.
7 *
8 * Copyright (C) 2006 Intel Corp.
9 * Tom Long Nguyen ([email protected])
10 * Zhang Yanmin ([email protected])
11 */
12
13#include <linux/pci.h>
14#include <linux/module.h>
2e28bc84
OP
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/aer.h>
18#include "portdrv.h"
19#include "../pci.h"
20
2e28bc84
OP
21static 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
542aeb9c
KB
46static int report_error_detected(struct pci_dev *dev,
47 enum pci_channel_state state,
48 enum pci_ers_result *result)
2e28bc84
OP
49{
50 pci_ers_result_t vote;
51 const struct pci_error_handlers *err_handler;
2e28bc84
OP
52
53 device_lock(&dev->dev);
a6bd101b
KB
54 if (!pci_dev_set_io_state(dev, state) ||
55 !dev->driver ||
2e28bc84
OP
56 !dev->driver->err_handler ||
57 !dev->driver->err_handler->error_detected) {
2e28bc84 58 /*
bfcb79fc
KB
59 * If any device in the subtree does not have an error_detected
60 * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
61 * error callbacks of "any" device in the subtree, and will
62 * exit in the disconnected error state.
2e28bc84 63 */
2e28bc84
OP
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;
542aeb9c 70 vote = err_handler->error_detected(dev, state);
2e28bc84 71 }
7b42d97e 72 pci_uevent_ers(dev, vote);
542aeb9c 73 *result = merge_result(*result, vote);
2e28bc84
OP
74 device_unlock(&dev->dev);
75 return 0;
76}
77
542aeb9c
KB
78static int report_frozen_detected(struct pci_dev *dev, void *data)
79{
80 return report_error_detected(dev, pci_channel_io_frozen, data);
81}
82
83static int report_normal_detected(struct pci_dev *dev, void *data)
84{
85 return report_error_detected(dev, pci_channel_io_normal, data);
86}
87
2e28bc84
OP
88static int report_mmio_enabled(struct pci_dev *dev, void *data)
89{
542aeb9c 90 pci_ers_result_t vote, *result = data;
2e28bc84 91 const struct pci_error_handlers *err_handler;
2e28bc84
OP
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);
542aeb9c 101 *result = merge_result(*result, vote);
2e28bc84
OP
102out:
103 device_unlock(&dev->dev);
104 return 0;
105}
106
107static int report_slot_reset(struct pci_dev *dev, void *data)
108{
542aeb9c 109 pci_ers_result_t vote, *result = data;
2e28bc84 110 const struct pci_error_handlers *err_handler;
2e28bc84
OP
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);
542aeb9c 120 *result = merge_result(*result, vote);
2e28bc84
OP
121out:
122 device_unlock(&dev->dev);
123 return 0;
124}
125
126static int report_resume(struct pci_dev *dev, void *data)
127{
128 const struct pci_error_handlers *err_handler;
129
130 device_lock(&dev->dev);
a6bd101b
KB
131 if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
132 !dev->driver ||
2e28bc84
OP
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);
2e28bc84 139out:
7b42d97e 140 pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
2e28bc84
OP
141 device_unlock(&dev->dev);
142 return 0;
143}
144
145/**
146 * default_reset_link - default reset function
147 * @dev: pointer to pci_dev data structure
148 *
149 * Invoked when performing link reset on a Downstream Port or a
150 * Root Port with no aer driver.
151 */
152static pci_ers_result_t default_reset_link(struct pci_dev *dev)
153{
18426238
SK
154 int rc;
155
c4eed62a 156 rc = pci_bus_error_reset(dev);
2e28bc84 157 pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
18426238 158 return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
2e28bc84
OP
159}
160
0b91439d 161static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
2e28bc84 162{
2e28bc84
OP
163 pci_ers_result_t status;
164 struct pcie_port_service_driver *driver = NULL;
165
bfcb79fc 166 driver = pcie_port_find_service(dev, service);
2e28bc84 167 if (driver && driver->reset_link) {
bfcb79fc
KB
168 status = driver->reset_link(dev);
169 } else if (dev->has_secondary_link) {
170 status = default_reset_link(dev);
2e28bc84
OP
171 } else {
172 pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
bfcb79fc 173 pci_name(dev));
2e28bc84
OP
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",
bfcb79fc 179 pci_name(dev));
2e28bc84
OP
180 return PCI_ERS_RESULT_DISCONNECT;
181 }
182
183 return status;
184}
185
bdb5ac85
KB
186void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
187 u32 service)
2e28bc84 188{
542aeb9c
KB
189 pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
190 struct pci_bus *bus;
2e28bc84 191
bfcb79fc
KB
192 /*
193 * Error recovery runs on all subordinates of the first downstream port.
194 * If the downstream port detected the error, it is cleared at the end.
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;
542aeb9c 199 bus = dev->subordinate;
bfcb79fc 200
542aeb9c
KB
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);
2e28bc84 206
bdb5ac85
KB
207 if (state == pci_channel_io_frozen &&
208 reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED)
209 goto failed;
210
542aeb9c
KB
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 }
2e28bc84
OP
216
217 if (status == PCI_ERS_RESULT_NEED_RESET) {
218 /*
219 * TODO: Should call platform-specific
220 * functions to reset slot before calling
221 * drivers' slot_reset callbacks?
222 */
542aeb9c
KB
223 status = PCI_ERS_RESULT_RECOVERED;
224 pci_dbg(dev, "broadcast slot_reset message\n");
225 pci_walk_bus(bus, report_slot_reset, &status);
2e28bc84
OP
226 }
227
228 if (status != PCI_ERS_RESULT_RECOVERED)
229 goto failed;
230
542aeb9c
KB
231 pci_dbg(dev, "broadcast resume message\n");
232 pci_walk_bus(bus, report_resume, &status);
2e28bc84 233
bfcb79fc
KB
234 pci_aer_clear_device_status(dev);
235 pci_cleanup_aer_uncorrect_error_status(dev);
2e28bc84
OP
236 pci_info(dev, "AER: Device recovery successful\n");
237 return;
238
239failed:
240 pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
241
242 /* TODO: Should kernel panic here? */
243 pci_info(dev, "AER: Device recovery failed\n");
244}
This page took 0.140525 seconds and 4 git commands to generate.