aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2018-09-20 12:27:14 -0400
committerBjorn Helgaas <bhelgaas@google.com>2018-10-02 17:04:40 -0400
commit542aeb9c8f930e4099432cb0bec17b92c0175e08 (patch)
tree8585dff3e123253286ab8e3e0b5653dba7666955
parentbfcb79fca19d267712e425af1dd48812c40dec0c (diff)
PCI/ERR: Simplify broadcast callouts
There is no point in having a generic broadcast function if it needs to have special cases for each callback it broadcasts. Abstract the error broadcast to only the necessary information and removes the now unnecessary helper to walk the bus. Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Sinan Kaya <okaya@kernel.org>
-rw-r--r--drivers/pci/pcie/err.c107
1 files changed, 38 insertions, 69 deletions
diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c
index 0fa5e1417a4a..362a717c831a 100644
--- a/drivers/pci/pcie/err.c
+++ b/drivers/pci/pcie/err.c
@@ -19,11 +19,6 @@
19#include "portdrv.h" 19#include "portdrv.h"
20#include "../pci.h" 20#include "../pci.h"
21 21
22struct aer_broadcast_data {
23 enum pci_channel_state state;
24 enum pci_ers_result result;
25};
26
27static pci_ers_result_t merge_result(enum pci_ers_result orig, 22static pci_ers_result_t merge_result(enum pci_ers_result orig,
28 enum pci_ers_result new) 23 enum pci_ers_result new)
29{ 24{
@@ -49,16 +44,15 @@ static pci_ers_result_t merge_result(enum pci_ers_result orig,
49 return orig; 44 return orig;
50} 45}
51 46
52static int report_error_detected(struct pci_dev *dev, void *data) 47static int report_error_detected(struct pci_dev *dev,
48 enum pci_channel_state state,
49 enum pci_ers_result *result)
53{ 50{
54 pci_ers_result_t vote; 51 pci_ers_result_t vote;
55 const struct pci_error_handlers *err_handler; 52 const struct pci_error_handlers *err_handler;
56 struct aer_broadcast_data *result_data;
57
58 result_data = (struct aer_broadcast_data *) data;
59 53
60 device_lock(&dev->dev); 54 device_lock(&dev->dev);
61 dev->error_state = result_data->state; 55 dev->error_state = state;
62 56
63 if (!dev->driver || 57 if (!dev->driver ||
64 !dev->driver->err_handler || 58 !dev->driver->err_handler ||
@@ -75,22 +69,29 @@ static int report_error_detected(struct pci_dev *dev, void *data)
75 vote = PCI_ERS_RESULT_NONE; 69 vote = PCI_ERS_RESULT_NONE;
76 } else { 70 } else {
77 err_handler = dev->driver->err_handler; 71 err_handler = dev->driver->err_handler;
78 vote = err_handler->error_detected(dev, result_data->state); 72 vote = err_handler->error_detected(dev, state);
79 pci_uevent_ers(dev, PCI_ERS_RESULT_NONE); 73 pci_uevent_ers(dev, PCI_ERS_RESULT_NONE);
80 } 74 }
81 75
82 result_data->result = merge_result(result_data->result, vote); 76 *result = merge_result(*result, vote);
83 device_unlock(&dev->dev); 77 device_unlock(&dev->dev);
84 return 0; 78 return 0;
85} 79}
86 80
81static int report_frozen_detected(struct pci_dev *dev, void *data)
82{
83 return report_error_detected(dev, pci_channel_io_frozen, data);
84}
85
86static int report_normal_detected(struct pci_dev *dev, void *data)
87{
88 return report_error_detected(dev, pci_channel_io_normal, data);
89}
90
87static int report_mmio_enabled(struct pci_dev *dev, void *data) 91static int report_mmio_enabled(struct pci_dev *dev, void *data)
88{ 92{
89 pci_ers_result_t vote; 93 pci_ers_result_t vote, *result = data;
90 const struct pci_error_handlers *err_handler; 94 const struct pci_error_handlers *err_handler;
91 struct aer_broadcast_data *result_data;
92
93 result_data = (struct aer_broadcast_data *) data;
94 95
95 device_lock(&dev->dev); 96 device_lock(&dev->dev);
96 if (!dev->driver || 97 if (!dev->driver ||
@@ -100,7 +101,7 @@ static int report_mmio_enabled(struct pci_dev *dev, void *data)
100 101
101 err_handler = dev->driver->err_handler; 102 err_handler = dev->driver->err_handler;
102 vote = err_handler->mmio_enabled(dev); 103 vote = err_handler->mmio_enabled(dev);
103 result_data->result = merge_result(result_data->result, vote); 104 *result = merge_result(*result, vote);
104out: 105out:
105 device_unlock(&dev->dev); 106 device_unlock(&dev->dev);
106 return 0; 107 return 0;
@@ -108,11 +109,8 @@ out:
108 109
109static int report_slot_reset(struct pci_dev *dev, void *data) 110static int report_slot_reset(struct pci_dev *dev, void *data)
110{ 111{
111 pci_ers_result_t vote; 112 pci_ers_result_t vote, *result = data;
112 const struct pci_error_handlers *err_handler; 113 const struct pci_error_handlers *err_handler;
113 struct aer_broadcast_data *result_data;
114
115 result_data = (struct aer_broadcast_data *) data;
116 114
117 device_lock(&dev->dev); 115 device_lock(&dev->dev);
118 if (!dev->driver || 116 if (!dev->driver ||
@@ -122,7 +120,7 @@ static int report_slot_reset(struct pci_dev *dev, void *data)
122 120
123 err_handler = dev->driver->err_handler; 121 err_handler = dev->driver->err_handler;
124 vote = err_handler->slot_reset(dev); 122 vote = err_handler->slot_reset(dev);
125 result_data->result = merge_result(result_data->result, vote); 123 *result = merge_result(*result, vote);
126out: 124out:
127 device_unlock(&dev->dev); 125 device_unlock(&dev->dev);
128 return 0; 126 return 0;
@@ -189,39 +187,11 @@ static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
189 return status; 187 return status;
190} 188}
191 189
192/**
193 * broadcast_error_message - handle message broadcast to downstream drivers
194 * @dev: pointer to from where in a hierarchy message is broadcasted down
195 * @state: error state
196 * @error_mesg: message to print
197 * @cb: callback to be broadcasted
198 *
199 * Invoked during error recovery process. Once being invoked, the content
200 * of error severity will be broadcasted to all downstream drivers in a
201 * hierarchy in question.
202 */
203static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
204 enum pci_channel_state state,
205 char *error_mesg,
206 int (*cb)(struct pci_dev *, void *))
207{
208 struct aer_broadcast_data result_data;
209
210 pci_printk(KERN_DEBUG, dev, "broadcast %s message\n", error_mesg);
211 result_data.state = state;
212 if (cb == report_error_detected)
213 result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
214 else
215 result_data.result = PCI_ERS_RESULT_RECOVERED;
216
217 pci_walk_bus(dev->subordinate, cb, &result_data);
218 return result_data.result;
219}
220
221void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, 190void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
222 u32 service) 191 u32 service)
223{ 192{
224 pci_ers_result_t status; 193 pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
194 struct pci_bus *bus;
225 195
226 /* 196 /*
227 * Error recovery runs on all subordinates of the first downstream port. 197 * Error recovery runs on all subordinates of the first downstream port.
@@ -230,21 +200,23 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
230 if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || 200 if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
231 pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)) 201 pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
232 dev = dev->bus->self; 202 dev = dev->bus->self;
203 bus = dev->subordinate;
233 204
234 status = broadcast_error_message(dev, 205 pci_dbg(dev, "broadcast error_detected message\n");
235 state, 206 if (state == pci_channel_io_frozen)
236 "error_detected", 207 pci_walk_bus(bus, report_frozen_detected, &status);
237 report_error_detected); 208 else
209 pci_walk_bus(bus, report_normal_detected, &status);
238 210
239 if (state == pci_channel_io_frozen && 211 if (state == pci_channel_io_frozen &&
240 reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED) 212 reset_link(dev, service) != PCI_ERS_RESULT_RECOVERED)
241 goto failed; 213 goto failed;
242 214
243 if (status == PCI_ERS_RESULT_CAN_RECOVER) 215 if (status == PCI_ERS_RESULT_CAN_RECOVER) {
244 status = broadcast_error_message(dev, 216 status = PCI_ERS_RESULT_RECOVERED;
245 state, 217 pci_dbg(dev, "broadcast mmio_enabled message\n");
246 "mmio_enabled", 218 pci_walk_bus(bus, report_mmio_enabled, &status);
247 report_mmio_enabled); 219 }
248 220
249 if (status == PCI_ERS_RESULT_NEED_RESET) { 221 if (status == PCI_ERS_RESULT_NEED_RESET) {
250 /* 222 /*
@@ -252,19 +224,16 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
252 * functions to reset slot before calling 224 * functions to reset slot before calling
253 * drivers' slot_reset callbacks? 225 * drivers' slot_reset callbacks?
254 */ 226 */
255 status = broadcast_error_message(dev, 227 status = PCI_ERS_RESULT_RECOVERED;
256 state, 228 pci_dbg(dev, "broadcast slot_reset message\n");
257 "slot_reset", 229 pci_walk_bus(bus, report_slot_reset, &status);
258 report_slot_reset);
259 } 230 }
260 231
261 if (status != PCI_ERS_RESULT_RECOVERED) 232 if (status != PCI_ERS_RESULT_RECOVERED)
262 goto failed; 233 goto failed;
263 234
264 broadcast_error_message(dev, 235 pci_dbg(dev, "broadcast resume message\n");
265 state, 236 pci_walk_bus(bus, report_resume, &status);
266 "resume",
267 report_resume);
268 237
269 pci_aer_clear_device_status(dev); 238 pci_aer_clear_device_status(dev);
270 pci_cleanup_aer_uncorrect_error_status(dev); 239 pci_cleanup_aer_uncorrect_error_status(dev);