aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/kernel/xpc_partition.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/sn/kernel/xpc_partition.c')
-rw-r--r--arch/ia64/sn/kernel/xpc_partition.c304
1 files changed, 254 insertions, 50 deletions
diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c
index 578265ea9e67..79a0fc4c860c 100644
--- a/arch/ia64/sn/kernel/xpc_partition.c
+++ b/arch/ia64/sn/kernel/xpc_partition.c
@@ -76,11 +76,6 @@ char ____cacheline_aligned
76 xpc_remote_copy_buffer[XPC_RSVD_PAGE_ALIGNED_SIZE]; 76 xpc_remote_copy_buffer[XPC_RSVD_PAGE_ALIGNED_SIZE];
77 77
78 78
79/* systune related variables */
80int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
81int xpc_hb_check_interval = XPC_HB_CHECK_DEFAULT_TIMEOUT;
82
83
84/* 79/*
85 * Given a nasid, get the physical address of the partition's reserved page 80 * Given a nasid, get the physical address of the partition's reserved page
86 * for that nasid. This function returns 0 on any error. 81 * for that nasid. This function returns 0 on any error.
@@ -239,16 +234,21 @@ xpc_rsvd_page_init(void)
239 xpc_vars->amos_page = amos_page; /* save for next load of XPC */ 234 xpc_vars->amos_page = amos_page; /* save for next load of XPC */
240 235
241 236
242 /* 237 /* initialize the activate IRQ related AMO variables */
243 * Initialize the activation related AMO variables. 238 for (i = 0; i < XP_NASID_MASK_WORDS; i++) {
244 */ 239 (void) xpc_IPI_init(XPC_ACTIVATE_IRQ_AMOS + i);
245 xpc_vars->act_amos = xpc_IPI_init(XP_MAX_PARTITIONS);
246 for (i = 1; i < XP_NASID_MASK_WORDS; i++) {
247 xpc_IPI_init(i + XP_MAX_PARTITIONS);
248 } 240 }
241
242 /* initialize the engaged remote partitions related AMO variables */
243 (void) xpc_IPI_init(XPC_ENGAGED_PARTITIONS_AMO);
244 (void) xpc_IPI_init(XPC_DISENGAGE_REQUEST_AMO);
245
249 /* export AMO page's physical address to other partitions */ 246 /* export AMO page's physical address to other partitions */
250 xpc_vars->amos_page_pa = ia64_tpa((u64) xpc_vars->amos_page); 247 xpc_vars->amos_page_pa = ia64_tpa((u64) xpc_vars->amos_page);
251 248
249 /* timestamp of when reserved page was initialized */
250 rp->stamp = CURRENT_TIME;
251
252 /* 252 /*
253 * This signifies to the remote partition that our reserved 253 * This signifies to the remote partition that our reserved
254 * page is initialized. 254 * page is initialized.
@@ -387,6 +387,11 @@ xpc_check_remote_hb(void)
387 remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer; 387 remote_vars = (struct xpc_vars *) xpc_remote_copy_buffer;
388 388
389 for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { 389 for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
390
391 if (xpc_exiting) {
392 break;
393 }
394
390 if (partid == sn_partition_id) { 395 if (partid == sn_partition_id) {
391 continue; 396 continue;
392 } 397 }
@@ -417,7 +422,7 @@ xpc_check_remote_hb(void)
417 422
418 if (((remote_vars->heartbeat == part->last_heartbeat) && 423 if (((remote_vars->heartbeat == part->last_heartbeat) &&
419 (remote_vars->kdb_status == 0)) || 424 (remote_vars->kdb_status == 0)) ||
420 !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) { 425 !xpc_hb_allowed(sn_partition_id, remote_vars)) {
421 426
422 XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat); 427 XPC_DEACTIVATE_PARTITION(part, xpcNoHeartbeat);
423 continue; 428 continue;
@@ -436,23 +441,23 @@ xpc_check_remote_hb(void)
436 */ 441 */
437static enum xpc_retval 442static enum xpc_retval
438xpc_get_remote_rp(int nasid, u64 *discovered_nasids, 443xpc_get_remote_rp(int nasid, u64 *discovered_nasids,
439 struct xpc_rsvd_page *remote_rp, u64 *remote_rsvd_page_pa) 444 struct xpc_rsvd_page *remote_rp, u64 *remote_rp_pa)
440{ 445{
441 int bres, i; 446 int bres, i;
442 447
443 448
444 /* get the reserved page's physical address */ 449 /* get the reserved page's physical address */
445 450
446 *remote_rsvd_page_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp, 451 *remote_rp_pa = xpc_get_rsvd_page_pa(nasid, (u64) remote_rp,
447 XPC_RSVD_PAGE_ALIGNED_SIZE); 452 XPC_RSVD_PAGE_ALIGNED_SIZE);
448 if (*remote_rsvd_page_pa == 0) { 453 if (*remote_rp_pa == 0) {
449 return xpcNoRsvdPageAddr; 454 return xpcNoRsvdPageAddr;
450 } 455 }
451 456
452 457
453 /* pull over the reserved page structure */ 458 /* pull over the reserved page structure */
454 459
455 bres = xp_bte_copy(*remote_rsvd_page_pa, ia64_tpa((u64) remote_rp), 460 bres = xp_bte_copy(*remote_rp_pa, ia64_tpa((u64) remote_rp),
456 XPC_RSVD_PAGE_ALIGNED_SIZE, 461 XPC_RSVD_PAGE_ALIGNED_SIZE,
457 (BTE_NOTIFY | BTE_WACQUIRE), NULL); 462 (BTE_NOTIFY | BTE_WACQUIRE), NULL);
458 if (bres != BTE_SUCCESS) { 463 if (bres != BTE_SUCCESS) {
@@ -524,6 +529,55 @@ xpc_get_remote_vars(u64 remote_vars_pa, struct xpc_vars *remote_vars)
524 529
525 530
526/* 531/*
532 * Update the remote partition's info.
533 */
534static void
535xpc_update_partition_info(struct xpc_partition *part, u8 remote_rp_version,
536 struct timespec *remote_rp_stamp, u64 remote_rp_pa,
537 u64 remote_vars_pa, struct xpc_vars *remote_vars)
538{
539 part->remote_rp_version = remote_rp_version;
540 dev_dbg(xpc_part, " remote_rp_version = 0x%016lx\n",
541 part->remote_rp_version);
542
543 part->remote_rp_stamp = *remote_rp_stamp;
544 dev_dbg(xpc_part, " remote_rp_stamp (tv_sec = 0x%lx tv_nsec = 0x%lx\n",
545 part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec);
546
547 part->remote_rp_pa = remote_rp_pa;
548 dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa);
549
550 part->remote_vars_pa = remote_vars_pa;
551 dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n",
552 part->remote_vars_pa);
553
554 part->last_heartbeat = remote_vars->heartbeat;
555 dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n",
556 part->last_heartbeat);
557
558 part->remote_vars_part_pa = remote_vars->vars_part_pa;
559 dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n",
560 part->remote_vars_part_pa);
561
562 part->remote_act_nasid = remote_vars->act_nasid;
563 dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n",
564 part->remote_act_nasid);
565
566 part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid;
567 dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n",
568 part->remote_act_phys_cpuid);
569
570 part->remote_amos_page_pa = remote_vars->amos_page_pa;
571 dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n",
572 part->remote_amos_page_pa);
573
574 part->remote_vars_version = remote_vars->version;
575 dev_dbg(xpc_part, " remote_vars_version = 0x%x\n",
576 part->remote_vars_version);
577}
578
579
580/*
527 * Prior code has determine the nasid which generated an IPI. Inspect 581 * Prior code has determine the nasid which generated an IPI. Inspect
528 * that nasid to determine if its partition needs to be activated or 582 * that nasid to determine if its partition needs to be activated or
529 * deactivated. 583 * deactivated.
@@ -542,8 +596,12 @@ xpc_identify_act_IRQ_req(int nasid)
542{ 596{
543 struct xpc_rsvd_page *remote_rp; 597 struct xpc_rsvd_page *remote_rp;
544 struct xpc_vars *remote_vars; 598 struct xpc_vars *remote_vars;
545 u64 remote_rsvd_page_pa; 599 u64 remote_rp_pa;
546 u64 remote_vars_pa; 600 u64 remote_vars_pa;
601 int remote_rp_version;
602 int reactivate = 0;
603 int stamp_diff;
604 struct timespec remote_rp_stamp = { 0, 0 };
547 partid_t partid; 605 partid_t partid;
548 struct xpc_partition *part; 606 struct xpc_partition *part;
549 enum xpc_retval ret; 607 enum xpc_retval ret;
@@ -553,7 +611,7 @@ xpc_identify_act_IRQ_req(int nasid)
553 611
554 remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer; 612 remote_rp = (struct xpc_rsvd_page *) xpc_remote_copy_buffer;
555 613
556 ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rsvd_page_pa); 614 ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa);
557 if (ret != xpcSuccess) { 615 if (ret != xpcSuccess) {
558 dev_warn(xpc_part, "unable to get reserved page from nasid %d, " 616 dev_warn(xpc_part, "unable to get reserved page from nasid %d, "
559 "which sent interrupt, reason=%d\n", nasid, ret); 617 "which sent interrupt, reason=%d\n", nasid, ret);
@@ -561,6 +619,10 @@ xpc_identify_act_IRQ_req(int nasid)
561 } 619 }
562 620
563 remote_vars_pa = remote_rp->vars_pa; 621 remote_vars_pa = remote_rp->vars_pa;
622 remote_rp_version = remote_rp->version;
623 if (XPC_SUPPORTS_RP_STAMP(remote_rp_version)) {
624 remote_rp_stamp = remote_rp->stamp;
625 }
564 partid = remote_rp->partid; 626 partid = remote_rp->partid;
565 part = &xpc_partitions[partid]; 627 part = &xpc_partitions[partid];
566 628
@@ -586,44 +648,117 @@ xpc_identify_act_IRQ_req(int nasid)
586 "%ld:0x%lx\n", (int) nasid, (int) partid, part->act_IRQ_rcvd, 648 "%ld:0x%lx\n", (int) nasid, (int) partid, part->act_IRQ_rcvd,
587 remote_vars->heartbeat, remote_vars->heartbeating_to_mask); 649 remote_vars->heartbeat, remote_vars->heartbeating_to_mask);
588 650
651 if (xpc_partition_disengaged(part) &&
652 part->act_state == XPC_P_INACTIVE) {
589 653
590 if (part->act_state == XPC_P_INACTIVE) { 654 xpc_update_partition_info(part, remote_rp_version,
655 &remote_rp_stamp, remote_rp_pa,
656 remote_vars_pa, remote_vars);
591 657
592 part->remote_rp_pa = remote_rsvd_page_pa; 658 if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) {
593 dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", 659 if (xpc_partition_disengage_requested(1UL << partid)) {
594 part->remote_rp_pa); 660 /*
661 * Other side is waiting on us to disengage,
662 * even though we already have.
663 */
664 return;
665 }
666 } else {
667 /* other side doesn't support disengage requests */
668 xpc_clear_partition_disengage_request(1UL << partid);
669 }
595 670
596 part->remote_vars_pa = remote_vars_pa; 671 xpc_activate_partition(part);
597 dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n", 672 return;
598 part->remote_vars_pa); 673 }
599 674
600 part->last_heartbeat = remote_vars->heartbeat; 675 DBUG_ON(part->remote_rp_version == 0);
601 dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n", 676 DBUG_ON(part->remote_vars_version == 0);
602 part->last_heartbeat); 677
678 if (!XPC_SUPPORTS_RP_STAMP(part->remote_rp_version)) {
679 DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(part->
680 remote_vars_version));
681
682 if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) {
683 DBUG_ON(XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->
684 version));
685 /* see if the other side rebooted */
686 if (part->remote_amos_page_pa ==
687 remote_vars->amos_page_pa &&
688 xpc_hb_allowed(sn_partition_id,
689 remote_vars)) {
690 /* doesn't look that way, so ignore the IPI */
691 return;
692 }
693 }
603 694
604 part->remote_vars_part_pa = remote_vars->vars_part_pa; 695 /*
605 dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n", 696 * Other side rebooted and previous XPC didn't support the
606 part->remote_vars_part_pa); 697 * disengage request, so we don't need to do anything special.
698 */
607 699
608 part->remote_act_nasid = remote_vars->act_nasid; 700 xpc_update_partition_info(part, remote_rp_version,
609 dev_dbg(xpc_part, " remote_act_nasid = 0x%x\n", 701 &remote_rp_stamp, remote_rp_pa,
610 part->remote_act_nasid); 702 remote_vars_pa, remote_vars);
703 part->reactivate_nasid = nasid;
704 XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
705 return;
706 }
611 707
612 part->remote_act_phys_cpuid = remote_vars->act_phys_cpuid; 708 DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version));
613 dev_dbg(xpc_part, " remote_act_phys_cpuid = 0x%x\n",
614 part->remote_act_phys_cpuid);
615 709
616 part->remote_amos_page_pa = remote_vars->amos_page_pa; 710 if (!XPC_SUPPORTS_RP_STAMP(remote_rp_version)) {
617 dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n", 711 DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version));
618 part->remote_amos_page_pa);
619 712
620 xpc_activate_partition(part); 713 /*
714 * Other side rebooted and previous XPC did support the
715 * disengage request, but the new one doesn't.
716 */
621 717
622 } else if (part->remote_amos_page_pa != remote_vars->amos_page_pa || 718 xpc_clear_partition_engaged(1UL << partid);
623 !XPC_HB_ALLOWED(sn_partition_id, remote_vars)) { 719 xpc_clear_partition_disengage_request(1UL << partid);
624 720
721 xpc_update_partition_info(part, remote_rp_version,
722 &remote_rp_stamp, remote_rp_pa,
723 remote_vars_pa, remote_vars);
724 reactivate = 1;
725
726 } else {
727 DBUG_ON(!XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->version));
728
729 stamp_diff = xpc_compare_stamps(&part->remote_rp_stamp,
730 &remote_rp_stamp);
731 if (stamp_diff != 0) {
732 DBUG_ON(stamp_diff >= 0);
733
734 /*
735 * Other side rebooted and the previous XPC did support
736 * the disengage request, as does the new one.
737 */
738
739 DBUG_ON(xpc_partition_engaged(1UL << partid));
740 DBUG_ON(xpc_partition_disengage_requested(1UL <<
741 partid));
742
743 xpc_update_partition_info(part, remote_rp_version,
744 &remote_rp_stamp, remote_rp_pa,
745 remote_vars_pa, remote_vars);
746 reactivate = 1;
747 }
748 }
749
750 if (!xpc_partition_disengaged(part)) {
751 /* still waiting on other side to disengage from us */
752 return;
753 }
754
755 if (reactivate) {
625 part->reactivate_nasid = nasid; 756 part->reactivate_nasid = nasid;
626 XPC_DEACTIVATE_PARTITION(part, xpcReactivating); 757 XPC_DEACTIVATE_PARTITION(part, xpcReactivating);
758
759 } else if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version) &&
760 xpc_partition_disengage_requested(1UL << partid)) {
761 XPC_DEACTIVATE_PARTITION(part, xpcOtherGoingDown);
627 } 762 }
628} 763}
629 764
@@ -646,12 +781,16 @@ xpc_identify_act_IRQ_sender(void)
646 struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page; 781 struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page;
647 782
648 783
649 act_amos = xpc_vars->act_amos; 784 act_amos = xpc_vars->amos_page + XPC_ACTIVATE_IRQ_AMOS;
650 785
651 786
652 /* scan through act AMO variable looking for non-zero entries */ 787 /* scan through act AMO variable looking for non-zero entries */
653 for (word = 0; word < XP_NASID_MASK_WORDS; word++) { 788 for (word = 0; word < XP_NASID_MASK_WORDS; word++) {
654 789
790 if (xpc_exiting) {
791 break;
792 }
793
655 nasid_mask = xpc_IPI_receive(&act_amos[word]); 794 nasid_mask = xpc_IPI_receive(&act_amos[word]);
656 if (nasid_mask == 0) { 795 if (nasid_mask == 0) {
657 /* no IRQs from nasids in this variable */ 796 /* no IRQs from nasids in this variable */
@@ -688,6 +827,55 @@ xpc_identify_act_IRQ_sender(void)
688 827
689 828
690/* 829/*
830 * See if the other side has responded to a partition disengage request
831 * from us.
832 */
833int
834xpc_partition_disengaged(struct xpc_partition *part)
835{
836 partid_t partid = XPC_PARTID(part);
837 int disengaged;
838
839
840 disengaged = (xpc_partition_engaged(1UL << partid) == 0);
841 if (part->disengage_request_timeout) {
842 if (!disengaged) {
843 if (jiffies < part->disengage_request_timeout) {
844 /* timelimit hasn't been reached yet */
845 return 0;
846 }
847
848 /*
849 * Other side hasn't responded to our disengage
850 * request in a timely fashion, so assume it's dead.
851 */
852
853 xpc_clear_partition_engaged(1UL << partid);
854 disengaged = 1;
855 }
856 part->disengage_request_timeout = 0;
857
858 /* cancel the timer function, provided it's not us */
859 if (!in_interrupt()) {
860 del_singleshot_timer_sync(&part->
861 disengage_request_timer);
862 }
863
864 DBUG_ON(part->act_state != XPC_P_DEACTIVATING &&
865 part->act_state != XPC_P_INACTIVE);
866 if (part->act_state != XPC_P_INACTIVE) {
867 xpc_wakeup_channel_mgr(part);
868 }
869
870 if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) {
871 xpc_cancel_partition_disengage_request(part);
872 }
873 }
874 return disengaged;
875}
876
877
878/*
691 * Mark specified partition as active. 879 * Mark specified partition as active.
692 */ 880 */
693enum xpc_retval 881enum xpc_retval
@@ -721,7 +909,6 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part,
721 enum xpc_retval reason) 909 enum xpc_retval reason)
722{ 910{
723 unsigned long irq_flags; 911 unsigned long irq_flags;
724 partid_t partid = XPC_PARTID(part);
725 912
726 913
727 spin_lock_irqsave(&part->act_lock, irq_flags); 914 spin_lock_irqsave(&part->act_lock, irq_flags);
@@ -749,17 +936,27 @@ xpc_deactivate_partition(const int line, struct xpc_partition *part,
749 936
750 spin_unlock_irqrestore(&part->act_lock, irq_flags); 937 spin_unlock_irqrestore(&part->act_lock, irq_flags);
751 938
752 XPC_DISALLOW_HB(partid, xpc_vars); 939 if (XPC_SUPPORTS_DISENGAGE_REQUEST(part->remote_vars_version)) {
940 xpc_request_partition_disengage(part);
941 xpc_IPI_send_disengage(part);
942
943 /* set a timelimit on the disengage request */
944 part->disengage_request_timeout = jiffies +
945 (XPC_DISENGAGE_REQUEST_TIMELIMIT * HZ);
946 part->disengage_request_timer.expires =
947 part->disengage_request_timeout;
948 add_timer(&part->disengage_request_timer);
949 }
753 950
754 dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", partid, 951 dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n", partid,
755 reason); 952 reason);
756 953
757 xpc_partition_down(part, reason); 954 xpc_partition_going_down(part, reason);
758} 955}
759 956
760 957
761/* 958/*
762 * Mark specified partition as active. 959 * Mark specified partition as inactive.
763 */ 960 */
764void 961void
765xpc_mark_partition_inactive(struct xpc_partition *part) 962xpc_mark_partition_inactive(struct xpc_partition *part)
@@ -792,7 +989,7 @@ xpc_discovery(void)
792 void *remote_rp_base; 989 void *remote_rp_base;
793 struct xpc_rsvd_page *remote_rp; 990 struct xpc_rsvd_page *remote_rp;
794 struct xpc_vars *remote_vars; 991 struct xpc_vars *remote_vars;
795 u64 remote_rsvd_page_pa; 992 u64 remote_rp_pa;
796 u64 remote_vars_pa; 993 u64 remote_vars_pa;
797 int region; 994 int region;
798 int max_regions; 995 int max_regions;
@@ -877,7 +1074,7 @@ xpc_discovery(void)
877 /* pull over the reserved page structure */ 1074 /* pull over the reserved page structure */
878 1075
879 ret = xpc_get_remote_rp(nasid, discovered_nasids, 1076 ret = xpc_get_remote_rp(nasid, discovered_nasids,
880 remote_rp, &remote_rsvd_page_pa); 1077 remote_rp, &remote_rp_pa);
881 if (ret != xpcSuccess) { 1078 if (ret != xpcSuccess) {
882 dev_dbg(xpc_part, "unable to get reserved page " 1079 dev_dbg(xpc_part, "unable to get reserved page "
883 "from nasid %d, reason=%d\n", nasid, 1080 "from nasid %d, reason=%d\n", nasid,
@@ -948,6 +1145,13 @@ xpc_discovery(void)
948 remote_vars->act_nasid, 1145 remote_vars->act_nasid,
949 remote_vars->act_phys_cpuid); 1146 remote_vars->act_phys_cpuid);
950 1147
1148 if (XPC_SUPPORTS_DISENGAGE_REQUEST(remote_vars->
1149 version)) {
1150 part->remote_amos_page_pa =
1151 remote_vars->amos_page_pa;
1152 xpc_mark_partition_disengaged(part);
1153 xpc_cancel_partition_disengage_request(part);
1154 }
951 xpc_IPI_send_activate(remote_vars); 1155 xpc_IPI_send_activate(remote_vars);
952 } 1156 }
953 } 1157 }