diff options
| author | Alexandre Bounine <alexandre.bounine@idt.com> | 2010-10-27 18:34:30 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:03:15 -0400 |
| commit | dd5648c9f53b5cbd9f948d752624400545f979fb (patch) | |
| tree | 9092a86701a6b4fa5cd722d4f3fc8b803d08b94c /drivers/rapidio | |
| parent | 68fe4df5d21294401959fa61d5a7094705ed8f6f (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')
| -rw-r--r-- | drivers/rapidio/rio.c | 218 | ||||
| -rw-r--r-- | drivers/rapidio/switches/idtcps.c | 10 | ||||
| -rw-r--r-- | drivers/rapidio/switches/tsi57x.c | 4 |
3 files changed, 201 insertions, 31 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 74e9d22d95f..77bd4165238 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 | */ | ||
| 504 | static int | ||
| 505 | rio_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 | ®val); | ||
| 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 | ®val); | ||
| 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 | */ | ||
| 552 | static 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, ®val)) { | ||
| 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 | ®val); | ||
| 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 | } | ||
| 616 | rd_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), |
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c index 2c790c144f8..fc9f6374f75 100644 --- a/drivers/rapidio/switches/idtcps.c +++ b/drivers/rapidio/switches/idtcps.c | |||
| @@ -117,6 +117,10 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, | |||
| 117 | 117 | ||
| 118 | static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) | 118 | static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) |
| 119 | { | 119 | { |
| 120 | struct rio_mport *mport = rdev->net->hport; | ||
| 121 | u16 destid = rdev->rswitch->destid; | ||
| 122 | u8 hopcount = rdev->rswitch->hopcount; | ||
| 123 | |||
| 120 | pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); | 124 | pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); |
| 121 | rdev->rswitch->add_entry = idtcps_route_add_entry; | 125 | rdev->rswitch->add_entry = idtcps_route_add_entry; |
| 122 | rdev->rswitch->get_entry = idtcps_route_get_entry; | 126 | rdev->rswitch->get_entry = idtcps_route_get_entry; |
| @@ -126,6 +130,12 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) | |||
| 126 | rdev->rswitch->em_init = NULL; | 130 | rdev->rswitch->em_init = NULL; |
| 127 | rdev->rswitch->em_handle = NULL; | 131 | rdev->rswitch->em_handle = NULL; |
| 128 | 132 | ||
| 133 | if (do_enum) { | ||
| 134 | /* set TVAL = ~50us */ | ||
| 135 | rio_mport_write_config_32(mport, destid, hopcount, | ||
| 136 | rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); | ||
| 137 | } | ||
| 138 | |||
| 129 | return 0; | 139 | return 0; |
| 130 | } | 140 | } |
| 131 | 141 | ||
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c index d34df722d95..d9e94920e8b 100644 --- a/drivers/rapidio/switches/tsi57x.c +++ b/drivers/rapidio/switches/tsi57x.c | |||
| @@ -205,6 +205,10 @@ tsi57x_em_init(struct rio_dev *rdev) | |||
| 205 | portnum++; | 205 | portnum++; |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | /* set TVAL = ~50us */ | ||
| 209 | rio_mport_write_config_32(mport, destid, hopcount, | ||
| 210 | rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8); | ||
| 211 | |||
| 208 | return 0; | 212 | return 0; |
| 209 | } | 213 | } |
| 210 | 214 | ||
