aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang, Yanmin <yanmin_zhang@linux.intel.com>2009-06-16 01:34:38 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-06-16 17:30:13 -0400
commit70298c6e6c1ba68346336b4ea54bd5c0abbf73c8 (patch)
tree363d0a784d8a28688c0fda006279563a7fd3629b
parenta6c0d5c6ebb3d988b1f18a1612b5188f3f555637 (diff)
PCI AER: support Multiple Error Received and no error source id
Based on PCI Express AER specs, a root port might receive multiple TLP errors while it could only save a correctable error source id and an uncorrectable error source id at the same time. In addition, some root port hardware might be unable to provide a correct source id, i.e., the source id, or the bus id part of the source id provided by root port might be equal to 0. The patchset implements the support in kernel by searching the device tree under the root port. Patch 1 changes parameter cb of function pci_walk_bus to return a value. When cb return non-zero, pci_walk_bus stops more searching on the device tree. Reviewed-by: Andrew Patterson <andrew.patterson@hp.com> Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c38
-rw-r--r--drivers/pci/bus.c11
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c30
-rw-r--r--include/linux/pci.h2
4 files changed, 50 insertions, 31 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 9a2a6e32f00f..0e8db6771252 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -122,7 +122,7 @@ static void eeh_enable_irq(struct pci_dev *dev)
122 * passed back in "userdata". 122 * passed back in "userdata".
123 */ 123 */
124 124
125static void eeh_report_error(struct pci_dev *dev, void *userdata) 125static int eeh_report_error(struct pci_dev *dev, void *userdata)
126{ 126{
127 enum pci_ers_result rc, *res = userdata; 127 enum pci_ers_result rc, *res = userdata;
128 struct pci_driver *driver = dev->driver; 128 struct pci_driver *driver = dev->driver;
@@ -130,19 +130,21 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
130 dev->error_state = pci_channel_io_frozen; 130 dev->error_state = pci_channel_io_frozen;
131 131
132 if (!driver) 132 if (!driver)
133 return; 133 return 0;
134 134
135 eeh_disable_irq(dev); 135 eeh_disable_irq(dev);
136 136
137 if (!driver->err_handler || 137 if (!driver->err_handler ||
138 !driver->err_handler->error_detected) 138 !driver->err_handler->error_detected)
139 return; 139 return 0;
140 140
141 rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); 141 rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen);
142 142
143 /* A driver that needs a reset trumps all others */ 143 /* A driver that needs a reset trumps all others */
144 if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 144 if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
145 if (*res == PCI_ERS_RESULT_NONE) *res = rc; 145 if (*res == PCI_ERS_RESULT_NONE) *res = rc;
146
147 return 0;
146} 148}
147 149
148/** 150/**
@@ -153,7 +155,7 @@ static void eeh_report_error(struct pci_dev *dev, void *userdata)
153 * Cumulative response passed back in "userdata". 155 * Cumulative response passed back in "userdata".
154 */ 156 */
155 157
156static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) 158static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
157{ 159{
158 enum pci_ers_result rc, *res = userdata; 160 enum pci_ers_result rc, *res = userdata;
159 struct pci_driver *driver = dev->driver; 161 struct pci_driver *driver = dev->driver;
@@ -161,26 +163,28 @@ static void eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata)
161 if (!driver || 163 if (!driver ||
162 !driver->err_handler || 164 !driver->err_handler ||
163 !driver->err_handler->mmio_enabled) 165 !driver->err_handler->mmio_enabled)
164 return; 166 return 0;
165 167
166 rc = driver->err_handler->mmio_enabled (dev); 168 rc = driver->err_handler->mmio_enabled (dev);
167 169
168 /* A driver that needs a reset trumps all others */ 170 /* A driver that needs a reset trumps all others */
169 if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 171 if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
170 if (*res == PCI_ERS_RESULT_NONE) *res = rc; 172 if (*res == PCI_ERS_RESULT_NONE) *res = rc;
173
174 return 0;
171} 175}
172 176
173/** 177/**
174 * eeh_report_reset - tell device that slot has been reset 178 * eeh_report_reset - tell device that slot has been reset
175 */ 179 */
176 180
177static void eeh_report_reset(struct pci_dev *dev, void *userdata) 181static int eeh_report_reset(struct pci_dev *dev, void *userdata)
178{ 182{
179 enum pci_ers_result rc, *res = userdata; 183 enum pci_ers_result rc, *res = userdata;
180 struct pci_driver *driver = dev->driver; 184 struct pci_driver *driver = dev->driver;
181 185
182 if (!driver) 186 if (!driver)
183 return; 187 return 0;
184 188
185 dev->error_state = pci_channel_io_normal; 189 dev->error_state = pci_channel_io_normal;
186 190
@@ -188,35 +192,39 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
188 192
189 if (!driver->err_handler || 193 if (!driver->err_handler ||
190 !driver->err_handler->slot_reset) 194 !driver->err_handler->slot_reset)
191 return; 195 return 0;
192 196
193 rc = driver->err_handler->slot_reset(dev); 197 rc = driver->err_handler->slot_reset(dev);
194 if ((*res == PCI_ERS_RESULT_NONE) || 198 if ((*res == PCI_ERS_RESULT_NONE) ||
195 (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc; 199 (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
196 if (*res == PCI_ERS_RESULT_DISCONNECT && 200 if (*res == PCI_ERS_RESULT_DISCONNECT &&
197 rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 201 rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
202
203 return 0;
198} 204}
199 205
200/** 206/**
201 * eeh_report_resume - tell device to resume normal operations 207 * eeh_report_resume - tell device to resume normal operations
202 */ 208 */
203 209
204static void eeh_report_resume(struct pci_dev *dev, void *userdata) 210static int eeh_report_resume(struct pci_dev *dev, void *userdata)
205{ 211{
206 struct pci_driver *driver = dev->driver; 212 struct pci_driver *driver = dev->driver;
207 213
208 dev->error_state = pci_channel_io_normal; 214 dev->error_state = pci_channel_io_normal;
209 215
210 if (!driver) 216 if (!driver)
211 return; 217 return 0;
212 218
213 eeh_enable_irq(dev); 219 eeh_enable_irq(dev);
214 220
215 if (!driver->err_handler || 221 if (!driver->err_handler ||
216 !driver->err_handler->resume) 222 !driver->err_handler->resume)
217 return; 223 return 0;
218 224
219 driver->err_handler->resume(dev); 225 driver->err_handler->resume(dev);
226
227 return 0;
220} 228}
221 229
222/** 230/**
@@ -226,22 +234,24 @@ static void eeh_report_resume(struct pci_dev *dev, void *userdata)
226 * dead, and that no further recovery attempts will be made on it. 234 * dead, and that no further recovery attempts will be made on it.
227 */ 235 */
228 236
229static void eeh_report_failure(struct pci_dev *dev, void *userdata) 237static int eeh_report_failure(struct pci_dev *dev, void *userdata)
230{ 238{
231 struct pci_driver *driver = dev->driver; 239 struct pci_driver *driver = dev->driver;
232 240
233 dev->error_state = pci_channel_io_perm_failure; 241 dev->error_state = pci_channel_io_perm_failure;
234 242
235 if (!driver) 243 if (!driver)
236 return; 244 return 0;
237 245
238 eeh_disable_irq(dev); 246 eeh_disable_irq(dev);
239 247
240 if (!driver->err_handler || 248 if (!driver->err_handler ||
241 !driver->err_handler->error_detected) 249 !driver->err_handler->error_detected)
242 return; 250 return 0;
243 251
244 driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); 252 driver->err_handler->error_detected(dev, pci_channel_io_perm_failure);
253
254 return 0;
245} 255}
246 256
247/* ------------------------------------------------------- */ 257/* ------------------------------------------------------- */
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 40af27f31043..cef28a79103f 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -206,13 +206,18 @@ void pci_enable_bridges(struct pci_bus *bus)
206 * Walk the given bus, including any bridged devices 206 * Walk the given bus, including any bridged devices
207 * on buses under this bus. Call the provided callback 207 * on buses under this bus. Call the provided callback
208 * on each device found. 208 * on each device found.
209 *
210 * We check the return of @cb each time. If it returns anything
211 * other than 0, we break out.
212 *
209 */ 213 */
210void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), 214void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
211 void *userdata) 215 void *userdata)
212{ 216{
213 struct pci_dev *dev; 217 struct pci_dev *dev;
214 struct pci_bus *bus; 218 struct pci_bus *bus;
215 struct list_head *next; 219 struct list_head *next;
220 int retval;
216 221
217 bus = top; 222 bus = top;
218 down_read(&pci_bus_sem); 223 down_read(&pci_bus_sem);
@@ -236,8 +241,10 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
236 241
237 /* Run device routines with the device locked */ 242 /* Run device routines with the device locked */
238 down(&dev->dev.sem); 243 down(&dev->dev.sem);
239 cb(dev, userdata); 244 retval = cb(dev, userdata);
240 up(&dev->dev.sem); 245 up(&dev->dev.sem);
246 if (retval)
247 break;
241 } 248 }
242 up_read(&pci_bus_sem); 249 up_read(&pci_bus_sem);
243} 250}
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index dd3829e68e3f..a7a3919904bb 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -109,7 +109,7 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
109#endif /* 0 */ 109#endif /* 0 */
110 110
111 111
112static void set_device_error_reporting(struct pci_dev *dev, void *data) 112static int set_device_error_reporting(struct pci_dev *dev, void *data)
113{ 113{
114 bool enable = *((bool *)data); 114 bool enable = *((bool *)data);
115 115
@@ -124,6 +124,8 @@ static void set_device_error_reporting(struct pci_dev *dev, void *data)
124 124
125 if (enable) 125 if (enable)
126 pcie_set_ecrc_checking(dev); 126 pcie_set_ecrc_checking(dev);
127
128 return 0;
127} 129}
128 130
129/** 131/**
@@ -207,7 +209,7 @@ static struct device* find_source_device(struct pci_dev *parent, u16 id)
207 return NULL; 209 return NULL;
208} 210}
209 211
210static void report_error_detected(struct pci_dev *dev, void *data) 212static int report_error_detected(struct pci_dev *dev, void *data)
211{ 213{
212 pci_ers_result_t vote; 214 pci_ers_result_t vote;
213 struct pci_error_handlers *err_handler; 215 struct pci_error_handlers *err_handler;
@@ -232,16 +234,16 @@ static void report_error_detected(struct pci_dev *dev, void *data)
232 dev->driver ? 234 dev->driver ?
233 "no AER-aware driver" : "no driver"); 235 "no AER-aware driver" : "no driver");
234 } 236 }
235 return; 237 return 0;
236 } 238 }
237 239
238 err_handler = dev->driver->err_handler; 240 err_handler = dev->driver->err_handler;
239 vote = err_handler->error_detected(dev, result_data->state); 241 vote = err_handler->error_detected(dev, result_data->state);
240 result_data->result = merge_result(result_data->result, vote); 242 result_data->result = merge_result(result_data->result, vote);
241 return; 243 return 0;
242} 244}
243 245
244static void report_mmio_enabled(struct pci_dev *dev, void *data) 246static int report_mmio_enabled(struct pci_dev *dev, void *data)
245{ 247{
246 pci_ers_result_t vote; 248 pci_ers_result_t vote;
247 struct pci_error_handlers *err_handler; 249 struct pci_error_handlers *err_handler;
@@ -251,15 +253,15 @@ static void report_mmio_enabled(struct pci_dev *dev, void *data)
251 if (!dev->driver || 253 if (!dev->driver ||
252 !dev->driver->err_handler || 254 !dev->driver->err_handler ||
253 !dev->driver->err_handler->mmio_enabled) 255 !dev->driver->err_handler->mmio_enabled)
254 return; 256 return 0;
255 257
256 err_handler = dev->driver->err_handler; 258 err_handler = dev->driver->err_handler;
257 vote = err_handler->mmio_enabled(dev); 259 vote = err_handler->mmio_enabled(dev);
258 result_data->result = merge_result(result_data->result, vote); 260 result_data->result = merge_result(result_data->result, vote);
259 return; 261 return 0;
260} 262}
261 263
262static void report_slot_reset(struct pci_dev *dev, void *data) 264static int report_slot_reset(struct pci_dev *dev, void *data)
263{ 265{
264 pci_ers_result_t vote; 266 pci_ers_result_t vote;
265 struct pci_error_handlers *err_handler; 267 struct pci_error_handlers *err_handler;
@@ -269,15 +271,15 @@ static void report_slot_reset(struct pci_dev *dev, void *data)
269 if (!dev->driver || 271 if (!dev->driver ||
270 !dev->driver->err_handler || 272 !dev->driver->err_handler ||
271 !dev->driver->err_handler->slot_reset) 273 !dev->driver->err_handler->slot_reset)
272 return; 274 return 0;
273 275
274 err_handler = dev->driver->err_handler; 276 err_handler = dev->driver->err_handler;
275 vote = err_handler->slot_reset(dev); 277 vote = err_handler->slot_reset(dev);
276 result_data->result = merge_result(result_data->result, vote); 278 result_data->result = merge_result(result_data->result, vote);
277 return; 279 return 0;
278} 280}
279 281
280static void report_resume(struct pci_dev *dev, void *data) 282static int report_resume(struct pci_dev *dev, void *data)
281{ 283{
282 struct pci_error_handlers *err_handler; 284 struct pci_error_handlers *err_handler;
283 285
@@ -286,11 +288,11 @@ static void report_resume(struct pci_dev *dev, void *data)
286 if (!dev->driver || 288 if (!dev->driver ||
287 !dev->driver->err_handler || 289 !dev->driver->err_handler ||
288 !dev->driver->err_handler->resume) 290 !dev->driver->err_handler->resume)
289 return; 291 return 0;
290 292
291 err_handler = dev->driver->err_handler; 293 err_handler = dev->driver->err_handler;
292 err_handler->resume(dev); 294 err_handler->resume(dev);
293 return; 295 return 0;
294} 296}
295 297
296/** 298/**
@@ -307,7 +309,7 @@ static void report_resume(struct pci_dev *dev, void *data)
307static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, 309static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
308 enum pci_channel_state state, 310 enum pci_channel_state state,
309 char *error_mesg, 311 char *error_mesg,
310 void (*cb)(struct pci_dev *, void *)) 312 int (*cb)(struct pci_dev *, void *))
311{ 313{
312 struct aer_broadcast_data result_data; 314 struct aer_broadcast_data result_data;
313 315
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6a1800ecd95d..61d9b790d21c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -789,7 +789,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
789int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, 789int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
790 int pass); 790 int pass);
791 791
792void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), 792void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
793 void *userdata); 793 void *userdata);
794int pci_cfg_space_size_ext(struct pci_dev *dev); 794int pci_cfg_space_size_ext(struct pci_dev *dev);
795int pci_cfg_space_size(struct pci_dev *dev); 795int pci_cfg_space_size(struct pci_dev *dev);