aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rapidio/rio.c
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2010-10-27 18:34:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-27 21:03:15 -0400
commitdd5648c9f53b5cbd9f948d752624400545f979fb (patch)
tree9092a86701a6b4fa5cd722d4f3fc8b803d08b94c /drivers/rapidio/rio.c
parent68fe4df5d21294401959fa61d5a7094705ed8f6f (diff)
rapidio: add default handler for error-stopped state
The default error-stopped state handler provides recovery mechanism as defined by RIO specification. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Thomas Moll <thomas.moll@sysgo.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Cc: Kumar Gala <galak@kernel.crashing.org> Cc: Micha Nelissen <micha@neli.hopto.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r--drivers/rapidio/rio.c218
1 files changed, 187 insertions, 31 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 74e9d22d95fb..77bd4165238f 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -495,6 +495,148 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
495} 495}
496 496
497/** 497/**
498 * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and
499 * returns link-response (if requested).
500 * @rdev: RIO devive to issue Input-status command
501 * @pnum: Device port number to issue the command
502 * @lnkresp: Response from a link partner
503 */
504static int
505rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
506{
507 struct rio_mport *mport = rdev->net->hport;
508 u16 destid = rdev->rswitch->destid;
509 u8 hopcount = rdev->rswitch->hopcount;
510 u32 regval;
511 int checkcount;
512
513 if (lnkresp) {
514 /* Read from link maintenance response register
515 * to clear valid bit */
516 rio_mport_read_config_32(mport, destid, hopcount,
517 rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
518 &regval);
519 udelay(50);
520 }
521
522 /* Issue Input-status command */
523 rio_mport_write_config_32(mport, destid, hopcount,
524 rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum),
525 RIO_MNT_REQ_CMD_IS);
526
527 /* Exit if the response is not expected */
528 if (lnkresp == NULL)
529 return 0;
530
531 checkcount = 3;
532 while (checkcount--) {
533 udelay(50);
534 rio_mport_read_config_32(mport, destid, hopcount,
535 rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
536 &regval);
537 if (regval & RIO_PORT_N_MNT_RSP_RVAL) {
538 *lnkresp = regval;
539 return 0;
540 }
541 }
542
543 return -EIO;
544}
545
546/**
547 * rio_clr_err_stopped - Clears port Error-stopped states.
548 * @rdev: Pointer to RIO device control structure
549 * @pnum: Switch port number to clear errors
550 * @err_status: port error status (if 0 reads register from device)
551 */
552static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
553{
554 struct rio_mport *mport = rdev->net->hport;
555 u16 destid = rdev->rswitch->destid;
556 u8 hopcount = rdev->rswitch->hopcount;
557 struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum];
558 u32 regval;
559 u32 far_ackid, far_linkstat, near_ackid;
560
561 if (err_status == 0)
562 rio_mport_read_config_32(mport, destid, hopcount,
563 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
564 &err_status);
565
566 if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
567 pr_debug("RIO_EM: servicing Output Error-Stopped state\n");
568 /*
569 * Send a Link-Request/Input-Status control symbol
570 */
571 if (rio_get_input_status(rdev, pnum, &regval)) {
572 pr_debug("RIO_EM: Input-status response timeout\n");
573 goto rd_err;
574 }
575
576 pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n",
577 pnum, regval);
578 far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
579 far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
580 rio_mport_read_config_32(mport, destid, hopcount,
581 rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
582 &regval);
583 pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval);
584 near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24;
585 pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \
586 " near_ackID=0x%02x\n",
587 pnum, far_ackid, far_linkstat, near_ackid);
588
589 /*
590 * If required, synchronize ackIDs of near and
591 * far sides.
592 */
593 if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) ||
594 (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) {
595 /* Align near outstanding/outbound ackIDs with
596 * far inbound.
597 */
598 rio_mport_write_config_32(mport, destid,
599 hopcount, rdev->phys_efptr +
600 RIO_PORT_N_ACK_STS_CSR(pnum),
601 (near_ackid << 24) |
602 (far_ackid << 8) | far_ackid);
603 /* Align far outstanding/outbound ackIDs with
604 * near inbound.
605 */
606 far_ackid++;
607 if (nextdev)
608 rio_write_config_32(nextdev,
609 nextdev->phys_efptr +
610 RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)),
611 (far_ackid << 24) |
612 (near_ackid << 8) | near_ackid);
613 else
614 pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n");
615 }
616rd_err:
617 rio_mport_read_config_32(mport, destid, hopcount,
618 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
619 &err_status);
620 pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
621 }
622
623 if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) {
624 pr_debug("RIO_EM: servicing Input Error-Stopped state\n");
625 rio_get_input_status(nextdev,
626 RIO_GET_PORT_NUM(nextdev->swpinfo), NULL);
627 udelay(50);
628
629 rio_mport_read_config_32(mport, destid, hopcount,
630 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
631 &err_status);
632 pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
633 }
634
635 return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
636 RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0;
637}
638
639/**
498 * rio_inb_pwrite_handler - process inbound port-write message 640 * rio_inb_pwrite_handler - process inbound port-write message
499 * @pw_msg: pointer to inbound port-write message 641 * @pw_msg: pointer to inbound port-write message
500 * 642 *
@@ -507,7 +649,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
507 struct rio_mport *mport; 649 struct rio_mport *mport;
508 u8 hopcount; 650 u8 hopcount;
509 u16 destid; 651 u16 destid;
510 u32 err_status; 652 u32 err_status, em_perrdet, em_ltlerrdet;
511 int rc, portnum; 653 int rc, portnum;
512 654
513 rdev = rio_get_comptag(pw_msg->em.comptag, NULL); 655 rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
@@ -524,12 +666,11 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
524 { 666 {
525 u32 i; 667 u32 i;
526 for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { 668 for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
527 pr_debug("0x%02x: %08x %08x %08x %08x", 669 pr_debug("0x%02x: %08x %08x %08x %08x\n",
528 i*4, pw_msg->raw[i], pw_msg->raw[i + 1], 670 i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
529 pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 671 pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
530 i += 4; 672 i += 4;
531 } 673 }
532 pr_debug("\n");
533 } 674 }
534#endif 675#endif
535 676
@@ -573,29 +714,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
573 &err_status); 714 &err_status);
574 pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 715 pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
575 716
576 if (pw_msg->em.errdetect) { 717 if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
577 pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
578 portnum, pw_msg->em.errdetect);
579 /* Clear EM Port N Error Detect CSR */
580 rio_mport_write_config_32(mport, destid, hopcount,
581 rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
582 }
583 718
584 if (pw_msg->em.ltlerrdet) { 719 if (!(rdev->rswitch->port_ok & (1 << portnum))) {
585 pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 720 rdev->rswitch->port_ok |= (1 << portnum);
586 pw_msg->em.ltlerrdet); 721 rio_set_port_lockout(rdev, portnum, 0);
587 /* Clear EM L/T Layer Error Detect CSR */ 722 /* Schedule Insertion Service */
588 rio_mport_write_config_32(mport, destid, hopcount, 723 pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
589 rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 724 rio_name(rdev), portnum);
590 } 725 }
591 726
592 /* Clear Port Errors */ 727 /* Clear error-stopped states (if reported).
593 rio_mport_write_config_32(mport, destid, hopcount, 728 * Depending on the link partner state, two attempts
594 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 729 * may be needed for successful recovery.
595 err_status & RIO_PORT_N_ERR_STS_CLR_MASK); 730 */
731 if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
732 RIO_PORT_N_ERR_STS_PW_INP_ES)) {
733 if (rio_clr_err_stopped(rdev, portnum, err_status))
734 rio_clr_err_stopped(rdev, portnum, 0);
735 }
736 } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */
596 737
597 if (rdev->rswitch->port_ok & (1 << portnum)) { 738 if (rdev->rswitch->port_ok & (1 << portnum)) {
598 if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
599 rdev->rswitch->port_ok &= ~(1 << portnum); 739 rdev->rswitch->port_ok &= ~(1 << portnum);
600 rio_set_port_lockout(rdev, portnum, 1); 740 rio_set_port_lockout(rdev, portnum, 1);
601 741
@@ -608,17 +748,33 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
608 pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 748 pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
609 rio_name(rdev), portnum); 749 rio_name(rdev), portnum);
610 } 750 }
611 } else { 751 }
612 if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
613 rdev->rswitch->port_ok |= (1 << portnum);
614 rio_set_port_lockout(rdev, portnum, 0);
615 752
616 /* Schedule Insertion Service */ 753 rio_mport_read_config_32(mport, destid, hopcount,
617 pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 754 rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
618 rio_name(rdev), portnum); 755 if (em_perrdet) {
619 } 756 pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
757 portnum, em_perrdet);
758 /* Clear EM Port N Error Detect CSR */
759 rio_mport_write_config_32(mport, destid, hopcount,
760 rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
620 } 761 }
621 762
763 rio_mport_read_config_32(mport, destid, hopcount,
764 rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
765 if (em_ltlerrdet) {
766 pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
767 em_ltlerrdet);
768 /* Clear EM L/T Layer Error Detect CSR */
769 rio_mport_write_config_32(mport, destid, hopcount,
770 rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
771 }
772
773 /* Clear remaining error bits */
774 rio_mport_write_config_32(mport, destid, hopcount,
775 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
776 err_status & RIO_PORT_N_ERR_STS_CLR_MASK);
777
622 /* Clear Port-Write Pending bit */ 778 /* Clear Port-Write Pending bit */
623 rio_mport_write_config_32(mport, destid, hopcount, 779 rio_mport_write_config_32(mport, destid, hopcount,
624 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 780 rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),