diff options
author | Dmitry Kalinkin <dmitry.kalinkin@gmail.com> | 2015-09-17 19:01:42 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-10-04 14:50:57 -0400 |
commit | e2c6393fda98dde5534dd6f83bd15f76abed6555 (patch) | |
tree | 73f94bb441c10040c6527b07c86e74d4a2eb1b37 /drivers/vme/bridges | |
parent | da5ae8a991d35d73b3875de0298afaf033d85363 (diff) |
vme: move tsi148 error handling into VME subsystem
Error handling code found in tsi148 is not device specific. In fact it
already relies on shared vme_bus_error struct and vme_bridge.vme_errors
field. The other bridge driver could reuse this code if it is shared.
This introduces a slight behavior change: vme error message won't be
triggered in a rare case when err_chk=1 and kmalloc fails.
Signed-off-by: Dmitry Kalinkin <dmitry.kalinkin@gmail.com>
Cc: Igor Alekseev <igor.alekseev@itep.ru>
Acked-by: Martyn Welch <martyn@welchs.me.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/vme/bridges')
-rw-r--r-- | drivers/vme/bridges/vme_tsi148.c | 93 |
1 files changed, 7 insertions, 86 deletions
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index 6c40f282c267..60c4933ca0c8 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c | |||
@@ -169,7 +169,6 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) | |||
169 | unsigned int error_addr_high, error_addr_low; | 169 | unsigned int error_addr_high, error_addr_low; |
170 | unsigned long long error_addr; | 170 | unsigned long long error_addr; |
171 | u32 error_attrib; | 171 | u32 error_attrib; |
172 | struct vme_bus_error *error = NULL; | ||
173 | struct tsi148_driver *bridge; | 172 | struct tsi148_driver *bridge; |
174 | 173 | ||
175 | bridge = tsi148_bridge->driver_priv; | 174 | bridge = tsi148_bridge->driver_priv; |
@@ -186,23 +185,12 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) | |||
186 | "Occurred\n"); | 185 | "Occurred\n"); |
187 | } | 186 | } |
188 | 187 | ||
189 | if (err_chk) { | 188 | if (err_chk) |
190 | error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC); | 189 | vme_bus_error_handler(tsi148_bridge, error_addr, error_attrib); |
191 | if (error) { | 190 | else |
192 | error->address = error_addr; | ||
193 | error->attributes = error_attrib; | ||
194 | list_add_tail(&error->list, &tsi148_bridge->vme_errors); | ||
195 | } else { | ||
196 | dev_err(tsi148_bridge->parent, | ||
197 | "Unable to alloc memory for VMEbus Error reporting\n"); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (!error) { | ||
202 | dev_err(tsi148_bridge->parent, | 191 | dev_err(tsi148_bridge->parent, |
203 | "VME Bus Error at address: 0x%llx, attributes: %08x\n", | 192 | "VME Bus Error at address: 0x%llx, attributes: %08x\n", |
204 | error_addr, error_attrib); | 193 | error_addr, error_attrib); |
205 | } | ||
206 | 194 | ||
207 | /* Clear Status */ | 195 | /* Clear Status */ |
208 | iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT); | 196 | iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT); |
@@ -483,73 +471,6 @@ static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, | |||
483 | } | 471 | } |
484 | 472 | ||
485 | /* | 473 | /* |
486 | * Find the first error in this address range | ||
487 | */ | ||
488 | static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge, | ||
489 | u32 aspace, unsigned long long address, size_t count) | ||
490 | { | ||
491 | struct list_head *err_pos; | ||
492 | struct vme_bus_error *vme_err, *valid = NULL; | ||
493 | unsigned long long bound; | ||
494 | |||
495 | bound = address + count; | ||
496 | |||
497 | /* | ||
498 | * XXX We are currently not looking at the address space when parsing | ||
499 | * for errors. This is because parsing the Address Modifier Codes | ||
500 | * is going to be quite resource intensive to do properly. We | ||
501 | * should be OK just looking at the addresses and this is certainly | ||
502 | * much better than what we had before. | ||
503 | */ | ||
504 | err_pos = NULL; | ||
505 | /* Iterate through errors */ | ||
506 | list_for_each(err_pos, &tsi148_bridge->vme_errors) { | ||
507 | vme_err = list_entry(err_pos, struct vme_bus_error, list); | ||
508 | if ((vme_err->address >= address) && | ||
509 | (vme_err->address < bound)) { | ||
510 | |||
511 | valid = vme_err; | ||
512 | break; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | return valid; | ||
517 | } | ||
518 | |||
519 | /* | ||
520 | * Clear errors in the provided address range. | ||
521 | */ | ||
522 | static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, | ||
523 | u32 aspace, unsigned long long address, size_t count) | ||
524 | { | ||
525 | struct list_head *err_pos, *temp; | ||
526 | struct vme_bus_error *vme_err; | ||
527 | unsigned long long bound; | ||
528 | |||
529 | bound = address + count; | ||
530 | |||
531 | /* | ||
532 | * XXX We are currently not looking at the address space when parsing | ||
533 | * for errors. This is because parsing the Address Modifier Codes | ||
534 | * is going to be quite resource intensive to do properly. We | ||
535 | * should be OK just looking at the addresses and this is certainly | ||
536 | * much better than what we had before. | ||
537 | */ | ||
538 | err_pos = NULL; | ||
539 | /* Iterate through errors */ | ||
540 | list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) { | ||
541 | vme_err = list_entry(err_pos, struct vme_bus_error, list); | ||
542 | |||
543 | if ((vme_err->address >= address) && | ||
544 | (vme_err->address < bound)) { | ||
545 | |||
546 | list_del(err_pos); | ||
547 | kfree(vme_err); | ||
548 | } | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Initialize a slave window with the requested attributes. | 474 | * Initialize a slave window with the requested attributes. |
554 | */ | 475 | */ |
555 | static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, | 476 | static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, |
@@ -1323,14 +1244,14 @@ out: | |||
1323 | __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle, | 1244 | __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle, |
1324 | &dwidth); | 1245 | &dwidth); |
1325 | 1246 | ||
1326 | vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset, | 1247 | vme_err = vme_find_error(tsi148_bridge, aspace, vme_base + offset, |
1327 | count); | 1248 | count); |
1328 | if (vme_err != NULL) { | 1249 | if (vme_err != NULL) { |
1329 | dev_err(image->parent->parent, "First VME read error detected " | 1250 | dev_err(image->parent->parent, "First VME read error detected " |
1330 | "an at address 0x%llx\n", vme_err->address); | 1251 | "an at address 0x%llx\n", vme_err->address); |
1331 | retval = vme_err->address - (vme_base + offset); | 1252 | retval = vme_err->address - (vme_base + offset); |
1332 | /* Clear down save errors in this address range */ | 1253 | /* Clear down save errors in this address range */ |
1333 | tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset, | 1254 | vme_clear_errors(tsi148_bridge, aspace, vme_base + offset, |
1334 | count); | 1255 | count); |
1335 | } | 1256 | } |
1336 | 1257 | ||
@@ -1422,14 +1343,14 @@ out: | |||
1422 | 1343 | ||
1423 | ioread16(bridge->flush_image->kern_base + 0x7F000); | 1344 | ioread16(bridge->flush_image->kern_base + 0x7F000); |
1424 | 1345 | ||
1425 | vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset, | 1346 | vme_err = vme_find_error(tsi148_bridge, aspace, vme_base + offset, |
1426 | count); | 1347 | count); |
1427 | if (vme_err != NULL) { | 1348 | if (vme_err != NULL) { |
1428 | dev_warn(tsi148_bridge->parent, "First VME write error detected" | 1349 | dev_warn(tsi148_bridge->parent, "First VME write error detected" |
1429 | " an at address 0x%llx\n", vme_err->address); | 1350 | " an at address 0x%llx\n", vme_err->address); |
1430 | retval = vme_err->address - (vme_base + offset); | 1351 | retval = vme_err->address - (vme_base + offset); |
1431 | /* Clear down save errors in this address range */ | 1352 | /* Clear down save errors in this address range */ |
1432 | tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset, | 1353 | vme_clear_errors(tsi148_bridge, aspace, vme_base + offset, |
1433 | count); | 1354 | count); |
1434 | } | 1355 | } |
1435 | 1356 | ||