summaryrefslogtreecommitdiffstats
path: root/drivers/vme/bridges
diff options
context:
space:
mode:
authorDmitry Kalinkin <dmitry.kalinkin@gmail.com>2015-09-17 19:01:42 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-10-04 14:50:57 -0400
commite2c6393fda98dde5534dd6f83bd15f76abed6555 (patch)
tree73f94bb441c10040c6527b07c86e74d4a2eb1b37 /drivers/vme/bridges
parentda5ae8a991d35d73b3875de0298afaf033d85363 (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.c93
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 */
488static 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 */
522static 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 */
555static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, 476static 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