diff options
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r-- | drivers/rapidio/rio.c | 427 |
1 files changed, 340 insertions, 87 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 74e9d22d95fb..86c9a091a2ff 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "rio.h" | 32 | #include "rio.h" |
33 | 33 | ||
34 | static LIST_HEAD(rio_mports); | 34 | static LIST_HEAD(rio_mports); |
35 | static unsigned char next_portid; | ||
35 | 36 | ||
36 | /** | 37 | /** |
37 | * rio_local_get_device_id - Get the base/extended device id for a port | 38 | * rio_local_get_device_id - Get the base/extended device id for a port |
@@ -68,9 +69,13 @@ int rio_request_inb_mbox(struct rio_mport *mport, | |||
68 | void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, | 69 | void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, |
69 | int slot)) | 70 | int slot)) |
70 | { | 71 | { |
71 | int rc = 0; | 72 | int rc = -ENOSYS; |
73 | struct resource *res; | ||
72 | 74 | ||
73 | struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); | 75 | if (mport->ops->open_inb_mbox == NULL) |
76 | goto out; | ||
77 | |||
78 | res = kmalloc(sizeof(struct resource), GFP_KERNEL); | ||
74 | 79 | ||
75 | if (res) { | 80 | if (res) { |
76 | rio_init_mbox_res(res, mbox, mbox); | 81 | rio_init_mbox_res(res, mbox, mbox); |
@@ -88,7 +93,7 @@ int rio_request_inb_mbox(struct rio_mport *mport, | |||
88 | /* Hook the inbound message callback */ | 93 | /* Hook the inbound message callback */ |
89 | mport->inb_msg[mbox].mcback = minb; | 94 | mport->inb_msg[mbox].mcback = minb; |
90 | 95 | ||
91 | rc = rio_open_inb_mbox(mport, dev_id, mbox, entries); | 96 | rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); |
92 | } else | 97 | } else |
93 | rc = -ENOMEM; | 98 | rc = -ENOMEM; |
94 | 99 | ||
@@ -106,10 +111,13 @@ int rio_request_inb_mbox(struct rio_mport *mport, | |||
106 | */ | 111 | */ |
107 | int rio_release_inb_mbox(struct rio_mport *mport, int mbox) | 112 | int rio_release_inb_mbox(struct rio_mport *mport, int mbox) |
108 | { | 113 | { |
109 | rio_close_inb_mbox(mport, mbox); | 114 | if (mport->ops->close_inb_mbox) { |
115 | mport->ops->close_inb_mbox(mport, mbox); | ||
110 | 116 | ||
111 | /* Release the mailbox resource */ | 117 | /* Release the mailbox resource */ |
112 | return release_resource(mport->inb_msg[mbox].res); | 118 | return release_resource(mport->inb_msg[mbox].res); |
119 | } else | ||
120 | return -ENOSYS; | ||
113 | } | 121 | } |
114 | 122 | ||
115 | /** | 123 | /** |
@@ -129,9 +137,13 @@ int rio_request_outb_mbox(struct rio_mport *mport, | |||
129 | int entries, | 137 | int entries, |
130 | void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) | 138 | void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) |
131 | { | 139 | { |
132 | int rc = 0; | 140 | int rc = -ENOSYS; |
141 | struct resource *res; | ||
133 | 142 | ||
134 | struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); | 143 | if (mport->ops->open_outb_mbox == NULL) |
144 | goto out; | ||
145 | |||
146 | res = kmalloc(sizeof(struct resource), GFP_KERNEL); | ||
135 | 147 | ||
136 | if (res) { | 148 | if (res) { |
137 | rio_init_mbox_res(res, mbox, mbox); | 149 | rio_init_mbox_res(res, mbox, mbox); |
@@ -149,7 +161,7 @@ int rio_request_outb_mbox(struct rio_mport *mport, | |||
149 | /* Hook the inbound message callback */ | 161 | /* Hook the inbound message callback */ |
150 | mport->outb_msg[mbox].mcback = moutb; | 162 | mport->outb_msg[mbox].mcback = moutb; |
151 | 163 | ||
152 | rc = rio_open_outb_mbox(mport, dev_id, mbox, entries); | 164 | rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); |
153 | } else | 165 | } else |
154 | rc = -ENOMEM; | 166 | rc = -ENOMEM; |
155 | 167 | ||
@@ -167,10 +179,13 @@ int rio_request_outb_mbox(struct rio_mport *mport, | |||
167 | */ | 179 | */ |
168 | int rio_release_outb_mbox(struct rio_mport *mport, int mbox) | 180 | int rio_release_outb_mbox(struct rio_mport *mport, int mbox) |
169 | { | 181 | { |
170 | rio_close_outb_mbox(mport, mbox); | 182 | if (mport->ops->close_outb_mbox) { |
183 | mport->ops->close_outb_mbox(mport, mbox); | ||
171 | 184 | ||
172 | /* Release the mailbox resource */ | 185 | /* Release the mailbox resource */ |
173 | return release_resource(mport->outb_msg[mbox].res); | 186 | return release_resource(mport->outb_msg[mbox].res); |
187 | } else | ||
188 | return -ENOSYS; | ||
174 | } | 189 | } |
175 | 190 | ||
176 | /** | 191 | /** |
@@ -443,7 +458,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local, | |||
443 | * @from is not %NULL, searches continue from next device on the global | 458 | * @from is not %NULL, searches continue from next device on the global |
444 | * list. | 459 | * list. |
445 | */ | 460 | */ |
446 | static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) | 461 | struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) |
447 | { | 462 | { |
448 | struct list_head *n; | 463 | struct list_head *n; |
449 | struct rio_dev *rdev; | 464 | struct rio_dev *rdev; |
@@ -471,16 +486,9 @@ exit: | |||
471 | */ | 486 | */ |
472 | int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) | 487 | int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) |
473 | { | 488 | { |
474 | u8 hopcount = 0xff; | ||
475 | u16 destid = rdev->destid; | ||
476 | u32 regval; | 489 | u32 regval; |
477 | 490 | ||
478 | if (rdev->rswitch) { | 491 | rio_read_config_32(rdev, |
479 | destid = rdev->rswitch->destid; | ||
480 | hopcount = rdev->rswitch->hopcount; | ||
481 | } | ||
482 | |||
483 | rio_mport_read_config_32(rdev->net->hport, destid, hopcount, | ||
484 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), | 492 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), |
485 | ®val); | 493 | ®val); |
486 | if (lock) | 494 | if (lock) |
@@ -488,13 +496,223 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) | |||
488 | else | 496 | else |
489 | regval &= ~RIO_PORT_N_CTL_LOCKOUT; | 497 | regval &= ~RIO_PORT_N_CTL_LOCKOUT; |
490 | 498 | ||
491 | rio_mport_write_config_32(rdev->net->hport, destid, hopcount, | 499 | rio_write_config_32(rdev, |
492 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), | 500 | rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), |
493 | regval); | 501 | regval); |
494 | return 0; | 502 | return 0; |
495 | } | 503 | } |
496 | 504 | ||
497 | /** | 505 | /** |
506 | * rio_chk_dev_route - Validate route to the specified device. | ||
507 | * @rdev: RIO device failed to respond | ||
508 | * @nrdev: Last active device on the route to rdev | ||
509 | * @npnum: nrdev's port number on the route to rdev | ||
510 | * | ||
511 | * Follows a route to the specified RIO device to determine the last available | ||
512 | * device (and corresponding RIO port) on the route. | ||
513 | */ | ||
514 | static int | ||
515 | rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) | ||
516 | { | ||
517 | u32 result; | ||
518 | int p_port, rc = -EIO; | ||
519 | struct rio_dev *prev = NULL; | ||
520 | |||
521 | /* Find switch with failed RIO link */ | ||
522 | while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { | ||
523 | if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { | ||
524 | prev = rdev->prev; | ||
525 | break; | ||
526 | } | ||
527 | rdev = rdev->prev; | ||
528 | } | ||
529 | |||
530 | if (prev == NULL) | ||
531 | goto err_out; | ||
532 | |||
533 | p_port = prev->rswitch->route_table[rdev->destid]; | ||
534 | |||
535 | if (p_port != RIO_INVALID_ROUTE) { | ||
536 | pr_debug("RIO: link failed on [%s]-P%d\n", | ||
537 | rio_name(prev), p_port); | ||
538 | *nrdev = prev; | ||
539 | *npnum = p_port; | ||
540 | rc = 0; | ||
541 | } else | ||
542 | pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); | ||
543 | err_out: | ||
544 | return rc; | ||
545 | } | ||
546 | |||
547 | /** | ||
548 | * rio_mport_chk_dev_access - Validate access to the specified device. | ||
549 | * @mport: Master port to send transactions | ||
550 | * @destid: Device destination ID in network | ||
551 | * @hopcount: Number of hops into the network | ||
552 | */ | ||
553 | int | ||
554 | rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) | ||
555 | { | ||
556 | int i = 0; | ||
557 | u32 tmp; | ||
558 | |||
559 | while (rio_mport_read_config_32(mport, destid, hopcount, | ||
560 | RIO_DEV_ID_CAR, &tmp)) { | ||
561 | i++; | ||
562 | if (i == RIO_MAX_CHK_RETRY) | ||
563 | return -EIO; | ||
564 | mdelay(1); | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | /** | ||
571 | * rio_chk_dev_access - Validate access to the specified device. | ||
572 | * @rdev: Pointer to RIO device control structure | ||
573 | */ | ||
574 | static int rio_chk_dev_access(struct rio_dev *rdev) | ||
575 | { | ||
576 | return rio_mport_chk_dev_access(rdev->net->hport, | ||
577 | rdev->destid, rdev->hopcount); | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and | ||
582 | * returns link-response (if requested). | ||
583 | * @rdev: RIO devive to issue Input-status command | ||
584 | * @pnum: Device port number to issue the command | ||
585 | * @lnkresp: Response from a link partner | ||
586 | */ | ||
587 | static int | ||
588 | rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) | ||
589 | { | ||
590 | u32 regval; | ||
591 | int checkcount; | ||
592 | |||
593 | if (lnkresp) { | ||
594 | /* Read from link maintenance response register | ||
595 | * to clear valid bit */ | ||
596 | rio_read_config_32(rdev, | ||
597 | rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), | ||
598 | ®val); | ||
599 | udelay(50); | ||
600 | } | ||
601 | |||
602 | /* Issue Input-status command */ | ||
603 | rio_write_config_32(rdev, | ||
604 | rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), | ||
605 | RIO_MNT_REQ_CMD_IS); | ||
606 | |||
607 | /* Exit if the response is not expected */ | ||
608 | if (lnkresp == NULL) | ||
609 | return 0; | ||
610 | |||
611 | checkcount = 3; | ||
612 | while (checkcount--) { | ||
613 | udelay(50); | ||
614 | rio_read_config_32(rdev, | ||
615 | rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), | ||
616 | ®val); | ||
617 | if (regval & RIO_PORT_N_MNT_RSP_RVAL) { | ||
618 | *lnkresp = regval; | ||
619 | return 0; | ||
620 | } | ||
621 | } | ||
622 | |||
623 | return -EIO; | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * rio_clr_err_stopped - Clears port Error-stopped states. | ||
628 | * @rdev: Pointer to RIO device control structure | ||
629 | * @pnum: Switch port number to clear errors | ||
630 | * @err_status: port error status (if 0 reads register from device) | ||
631 | */ | ||
632 | static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) | ||
633 | { | ||
634 | struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; | ||
635 | u32 regval; | ||
636 | u32 far_ackid, far_linkstat, near_ackid; | ||
637 | |||
638 | if (err_status == 0) | ||
639 | rio_read_config_32(rdev, | ||
640 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), | ||
641 | &err_status); | ||
642 | |||
643 | if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) { | ||
644 | pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); | ||
645 | /* | ||
646 | * Send a Link-Request/Input-Status control symbol | ||
647 | */ | ||
648 | if (rio_get_input_status(rdev, pnum, ®val)) { | ||
649 | pr_debug("RIO_EM: Input-status response timeout\n"); | ||
650 | goto rd_err; | ||
651 | } | ||
652 | |||
653 | pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", | ||
654 | pnum, regval); | ||
655 | far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; | ||
656 | far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; | ||
657 | rio_read_config_32(rdev, | ||
658 | rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), | ||
659 | ®val); | ||
660 | pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); | ||
661 | near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; | ||
662 | pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ | ||
663 | " near_ackID=0x%02x\n", | ||
664 | pnum, far_ackid, far_linkstat, near_ackid); | ||
665 | |||
666 | /* | ||
667 | * If required, synchronize ackIDs of near and | ||
668 | * far sides. | ||
669 | */ | ||
670 | if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || | ||
671 | (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { | ||
672 | /* Align near outstanding/outbound ackIDs with | ||
673 | * far inbound. | ||
674 | */ | ||
675 | rio_write_config_32(rdev, | ||
676 | rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), | ||
677 | (near_ackid << 24) | | ||
678 | (far_ackid << 8) | far_ackid); | ||
679 | /* Align far outstanding/outbound ackIDs with | ||
680 | * near inbound. | ||
681 | */ | ||
682 | far_ackid++; | ||
683 | if (nextdev) | ||
684 | rio_write_config_32(nextdev, | ||
685 | nextdev->phys_efptr + | ||
686 | RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)), | ||
687 | (far_ackid << 24) | | ||
688 | (near_ackid << 8) | near_ackid); | ||
689 | else | ||
690 | pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); | ||
691 | } | ||
692 | rd_err: | ||
693 | rio_read_config_32(rdev, | ||
694 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), | ||
695 | &err_status); | ||
696 | pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); | ||
697 | } | ||
698 | |||
699 | if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) { | ||
700 | pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); | ||
701 | rio_get_input_status(nextdev, | ||
702 | RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); | ||
703 | udelay(50); | ||
704 | |||
705 | rio_read_config_32(rdev, | ||
706 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), | ||
707 | &err_status); | ||
708 | pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); | ||
709 | } | ||
710 | |||
711 | return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | | ||
712 | RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0; | ||
713 | } | ||
714 | |||
715 | /** | ||
498 | * rio_inb_pwrite_handler - process inbound port-write message | 716 | * rio_inb_pwrite_handler - process inbound port-write message |
499 | * @pw_msg: pointer to inbound port-write message | 717 | * @pw_msg: pointer to inbound port-write message |
500 | * | 718 | * |
@@ -504,16 +722,13 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) | |||
504 | int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) | 722 | int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) |
505 | { | 723 | { |
506 | struct rio_dev *rdev; | 724 | struct rio_dev *rdev; |
507 | struct rio_mport *mport; | 725 | u32 err_status, em_perrdet, em_ltlerrdet; |
508 | u8 hopcount; | ||
509 | u16 destid; | ||
510 | u32 err_status; | ||
511 | int rc, portnum; | 726 | int rc, portnum; |
512 | 727 | ||
513 | rdev = rio_get_comptag(pw_msg->em.comptag, NULL); | 728 | rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); |
514 | if (rdev == NULL) { | 729 | if (rdev == NULL) { |
515 | /* Someting bad here (probably enumeration error) */ | 730 | /* Device removed or enumeration error */ |
516 | pr_err("RIO: %s No matching device for CTag 0x%08x\n", | 731 | pr_debug("RIO: %s No matching device for CTag 0x%08x\n", |
517 | __func__, pw_msg->em.comptag); | 732 | __func__, pw_msg->em.comptag); |
518 | return -EIO; | 733 | return -EIO; |
519 | } | 734 | } |
@@ -524,12 +739,11 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) | |||
524 | { | 739 | { |
525 | u32 i; | 740 | u32 i; |
526 | for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { | 741 | for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { |
527 | pr_debug("0x%02x: %08x %08x %08x %08x", | 742 | pr_debug("0x%02x: %08x %08x %08x %08x\n", |
528 | i*4, pw_msg->raw[i], pw_msg->raw[i + 1], | 743 | i*4, pw_msg->raw[i], pw_msg->raw[i + 1], |
529 | pw_msg->raw[i + 2], pw_msg->raw[i + 3]); | 744 | pw_msg->raw[i + 2], pw_msg->raw[i + 3]); |
530 | i += 4; | 745 | i += 4; |
531 | } | 746 | } |
532 | pr_debug("\n"); | ||
533 | } | 747 | } |
534 | #endif | 748 | #endif |
535 | 749 | ||
@@ -545,6 +759,26 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) | |||
545 | return 0; | 759 | return 0; |
546 | } | 760 | } |
547 | 761 | ||
762 | portnum = pw_msg->em.is_port & 0xFF; | ||
763 | |||
764 | /* Check if device and route to it are functional: | ||
765 | * Sometimes devices may send PW message(s) just before being | ||
766 | * powered down (or link being lost). | ||
767 | */ | ||
768 | if (rio_chk_dev_access(rdev)) { | ||
769 | pr_debug("RIO: device access failed - get link partner\n"); | ||
770 | /* Scan route to the device and identify failed link. | ||
771 | * This will replace device and port reported in PW message. | ||
772 | * PW message should not be used after this point. | ||
773 | */ | ||
774 | if (rio_chk_dev_route(rdev, &rdev, &portnum)) { | ||
775 | pr_err("RIO: Route trace for %s failed\n", | ||
776 | rio_name(rdev)); | ||
777 | return -EIO; | ||
778 | } | ||
779 | pw_msg = NULL; | ||
780 | } | ||
781 | |||
548 | /* For End-point devices processing stops here */ | 782 | /* For End-point devices processing stops here */ |
549 | if (!(rdev->pef & RIO_PEF_SWITCH)) | 783 | if (!(rdev->pef & RIO_PEF_SWITCH)) |
550 | return 0; | 784 | return 0; |
@@ -555,51 +789,43 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) | |||
555 | return 0; | 789 | return 0; |
556 | } | 790 | } |
557 | 791 | ||
558 | mport = rdev->net->hport; | ||
559 | destid = rdev->rswitch->destid; | ||
560 | hopcount = rdev->rswitch->hopcount; | ||
561 | |||
562 | /* | 792 | /* |
563 | * Process the port-write notification from switch | 793 | * Process the port-write notification from switch |
564 | */ | 794 | */ |
565 | |||
566 | portnum = pw_msg->em.is_port & 0xFF; | ||
567 | |||
568 | if (rdev->rswitch->em_handle) | 795 | if (rdev->rswitch->em_handle) |
569 | rdev->rswitch->em_handle(rdev, portnum); | 796 | rdev->rswitch->em_handle(rdev, portnum); |
570 | 797 | ||
571 | rio_mport_read_config_32(mport, destid, hopcount, | 798 | rio_read_config_32(rdev, |
572 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), | 799 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), |
573 | &err_status); | 800 | &err_status); |
574 | pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); | 801 | pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); |
575 | 802 | ||
576 | if (pw_msg->em.errdetect) { | 803 | 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 | 804 | ||
584 | if (pw_msg->em.ltlerrdet) { | 805 | if (!(rdev->rswitch->port_ok & (1 << portnum))) { |
585 | pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", | 806 | rdev->rswitch->port_ok |= (1 << portnum); |
586 | pw_msg->em.ltlerrdet); | 807 | rio_set_port_lockout(rdev, portnum, 0); |
587 | /* Clear EM L/T Layer Error Detect CSR */ | 808 | /* Schedule Insertion Service */ |
588 | rio_mport_write_config_32(mport, destid, hopcount, | 809 | pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", |
589 | rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); | 810 | rio_name(rdev), portnum); |
590 | } | 811 | } |
591 | 812 | ||
592 | /* Clear Port Errors */ | 813 | /* Clear error-stopped states (if reported). |
593 | rio_mport_write_config_32(mport, destid, hopcount, | 814 | * Depending on the link partner state, two attempts |
594 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), | 815 | * may be needed for successful recovery. |
595 | err_status & RIO_PORT_N_ERR_STS_CLR_MASK); | 816 | */ |
817 | if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | | ||
818 | RIO_PORT_N_ERR_STS_PW_INP_ES)) { | ||
819 | if (rio_clr_err_stopped(rdev, portnum, err_status)) | ||
820 | rio_clr_err_stopped(rdev, portnum, 0); | ||
821 | } | ||
822 | } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ | ||
596 | 823 | ||
597 | if (rdev->rswitch->port_ok & (1 << portnum)) { | 824 | 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); | 825 | rdev->rswitch->port_ok &= ~(1 << portnum); |
600 | rio_set_port_lockout(rdev, portnum, 1); | 826 | rio_set_port_lockout(rdev, portnum, 1); |
601 | 827 | ||
602 | rio_mport_write_config_32(mport, destid, hopcount, | 828 | rio_write_config_32(rdev, |
603 | rdev->phys_efptr + | 829 | rdev->phys_efptr + |
604 | RIO_PORT_N_ACK_STS_CSR(portnum), | 830 | RIO_PORT_N_ACK_STS_CSR(portnum), |
605 | RIO_PORT_N_ACK_CLEAR); | 831 | RIO_PORT_N_ACK_CLEAR); |
@@ -608,21 +834,32 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) | |||
608 | pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", | 834 | pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", |
609 | rio_name(rdev), portnum); | 835 | rio_name(rdev), portnum); |
610 | } | 836 | } |
611 | } else { | 837 | } |
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 | 838 | ||
616 | /* Schedule Insertion Service */ | 839 | rio_read_config_32(rdev, |
617 | pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", | 840 | rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); |
618 | rio_name(rdev), portnum); | 841 | if (em_perrdet) { |
619 | } | 842 | pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", |
843 | portnum, em_perrdet); | ||
844 | /* Clear EM Port N Error Detect CSR */ | ||
845 | rio_write_config_32(rdev, | ||
846 | rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); | ||
620 | } | 847 | } |
621 | 848 | ||
622 | /* Clear Port-Write Pending bit */ | 849 | rio_read_config_32(rdev, |
623 | rio_mport_write_config_32(mport, destid, hopcount, | 850 | rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); |
851 | if (em_ltlerrdet) { | ||
852 | pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", | ||
853 | em_ltlerrdet); | ||
854 | /* Clear EM L/T Layer Error Detect CSR */ | ||
855 | rio_write_config_32(rdev, | ||
856 | rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); | ||
857 | } | ||
858 | |||
859 | /* Clear remaining error bits and Port-Write Pending bit */ | ||
860 | rio_write_config_32(rdev, | ||
624 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), | 861 | rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), |
625 | RIO_PORT_N_ERR_STS_PW_PEND); | 862 | err_status); |
626 | 863 | ||
627 | return 0; | 864 | return 0; |
628 | } | 865 | } |
@@ -898,37 +1135,53 @@ static int __devinit rio_init(void) | |||
898 | return 0; | 1135 | return 0; |
899 | } | 1136 | } |
900 | 1137 | ||
901 | device_initcall(rio_init); | ||
902 | |||
903 | int __devinit rio_init_mports(void) | 1138 | int __devinit rio_init_mports(void) |
904 | { | 1139 | { |
905 | int rc = 0; | ||
906 | struct rio_mport *port; | 1140 | struct rio_mport *port; |
907 | 1141 | ||
908 | list_for_each_entry(port, &rio_mports, node) { | 1142 | list_for_each_entry(port, &rio_mports, node) { |
909 | if (!request_mem_region(port->iores.start, | ||
910 | port->iores.end - port->iores.start, | ||
911 | port->name)) { | ||
912 | printk(KERN_ERR | ||
913 | "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", | ||
914 | (u64)port->iores.start, (u64)port->iores.end - 1); | ||
915 | rc = -ENOMEM; | ||
916 | goto out; | ||
917 | } | ||
918 | |||
919 | if (port->host_deviceid >= 0) | 1143 | if (port->host_deviceid >= 0) |
920 | rio_enum_mport(port); | 1144 | rio_enum_mport(port); |
921 | else | 1145 | else |
922 | rio_disc_mport(port); | 1146 | rio_disc_mport(port); |
923 | } | 1147 | } |
924 | 1148 | ||
925 | out: | 1149 | rio_init(); |
926 | return rc; | 1150 | |
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | device_initcall_sync(rio_init_mports); | ||
1155 | |||
1156 | static int hdids[RIO_MAX_MPORTS + 1]; | ||
1157 | |||
1158 | static int rio_get_hdid(int index) | ||
1159 | { | ||
1160 | if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS) | ||
1161 | return -1; | ||
1162 | |||
1163 | return hdids[index + 1]; | ||
927 | } | 1164 | } |
928 | 1165 | ||
929 | void rio_register_mport(struct rio_mport *port) | 1166 | static int rio_hdid_setup(char *str) |
930 | { | 1167 | { |
1168 | (void)get_options(str, ARRAY_SIZE(hdids), hdids); | ||
1169 | return 1; | ||
1170 | } | ||
1171 | |||
1172 | __setup("riohdid=", rio_hdid_setup); | ||
1173 | |||
1174 | int rio_register_mport(struct rio_mport *port) | ||
1175 | { | ||
1176 | if (next_portid >= RIO_MAX_MPORTS) { | ||
1177 | pr_err("RIO: reached specified max number of mports\n"); | ||
1178 | return 1; | ||
1179 | } | ||
1180 | |||
1181 | port->id = next_portid++; | ||
1182 | port->host_deviceid = rio_get_hdid(port->id); | ||
931 | list_add_tail(&port->node, &rio_mports); | 1183 | list_add_tail(&port->node, &rio_mports); |
1184 | return 0; | ||
932 | } | 1185 | } |
933 | 1186 | ||
934 | EXPORT_SYMBOL_GPL(rio_local_get_device_id); | 1187 | EXPORT_SYMBOL_GPL(rio_local_get_device_id); |