diff options
author | Cliff Wickman <cpw@sgi.com> | 2014-05-14 17:15:47 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-06-05 08:17:20 -0400 |
commit | a26fd71953711acb4884df84e393d52de57e4f17 (patch) | |
tree | 327923aa12694c97e56b398c12a259919db87c75 /arch/x86/platform | |
parent | fe455b17de6c881eecf4f9784c3b0483a5e3d19e (diff) |
x86/uv: Update the UV3 TLB shootdown logic
Update of TLB shootdown code for UV3.
Kernel function native_flush_tlb_others() calls
uv_flush_tlb_others() on UV to invalidate tlb page definitions
on remote cpus. The UV systems have a hardware 'broadcast assist
unit' which can be used to broadcast shootdown messages to all
cpu's of selected nodes.
The behavior of the BAU has changed only slightly with UV3:
- UV3 is recognized with is_uv3_hub().
- UV2 functions and structures (uv2_xxx) are in most cases
simply renamed to uv2_3_xxx.
- Some UV2 error workarounds are not needed for UV3.
(see uv_bau_message_interrupt and enable_timeouts)
Signed-off-by: Cliff Wickman <cpw@sgi.com>
Link: http://lkml.kernel.org/r/E1WkgWh-0001yJ-3K@eag09.americas.sgi.com
[ Removed a few linebreak uglies. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/uv/tlb_uv.c | 69 |
1 files changed, 38 insertions, 31 deletions
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index dfe605ac1bcd..ed161c6e278b 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SGI UltraViolet TLB flush routines. | 2 | * SGI UltraViolet TLB flush routines. |
3 | * | 3 | * |
4 | * (c) 2008-2012 Cliff Wickman <cpw@sgi.com>, SGI. | 4 | * (c) 2008-2014 Cliff Wickman <cpw@sgi.com>, SGI. |
5 | * | 5 | * |
6 | * This code is released under the GNU General Public License version 2 or | 6 | * This code is released under the GNU General Public License version 2 or |
7 | * later. | 7 | * later. |
@@ -451,7 +451,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) | |||
451 | 451 | ||
452 | /* | 452 | /* |
453 | * The reverse of the above; converts a duration in ns to a duration in cycles. | 453 | * The reverse of the above; converts a duration in ns to a duration in cycles. |
454 | */ | 454 | */ |
455 | static inline unsigned long long ns_2_cycles(unsigned long long ns) | 455 | static inline unsigned long long ns_2_cycles(unsigned long long ns) |
456 | { | 456 | { |
457 | struct cyc2ns_data *data = cyc2ns_read_begin(); | 457 | struct cyc2ns_data *data = cyc2ns_read_begin(); |
@@ -563,7 +563,7 @@ static int uv1_wait_completion(struct bau_desc *bau_desc, | |||
563 | * UV2 could have an extra bit of status in the ACTIVATION_STATUS_2 register. | 563 | * UV2 could have an extra bit of status in the ACTIVATION_STATUS_2 register. |
564 | * But not currently used. | 564 | * But not currently used. |
565 | */ | 565 | */ |
566 | static unsigned long uv2_read_status(unsigned long offset, int rshft, int desc) | 566 | static unsigned long uv2_3_read_status(unsigned long offset, int rshft, int desc) |
567 | { | 567 | { |
568 | unsigned long descriptor_status; | 568 | unsigned long descriptor_status; |
569 | 569 | ||
@@ -606,7 +606,7 @@ int handle_uv2_busy(struct bau_control *bcp) | |||
606 | return FLUSH_GIVEUP; | 606 | return FLUSH_GIVEUP; |
607 | } | 607 | } |
608 | 608 | ||
609 | static int uv2_wait_completion(struct bau_desc *bau_desc, | 609 | static int uv2_3_wait_completion(struct bau_desc *bau_desc, |
610 | unsigned long mmr_offset, int right_shift, | 610 | unsigned long mmr_offset, int right_shift, |
611 | struct bau_control *bcp, long try) | 611 | struct bau_control *bcp, long try) |
612 | { | 612 | { |
@@ -616,7 +616,7 @@ static int uv2_wait_completion(struct bau_desc *bau_desc, | |||
616 | long busy_reps = 0; | 616 | long busy_reps = 0; |
617 | struct ptc_stats *stat = bcp->statp; | 617 | struct ptc_stats *stat = bcp->statp; |
618 | 618 | ||
619 | descriptor_stat = uv2_read_status(mmr_offset, right_shift, desc); | 619 | descriptor_stat = uv2_3_read_status(mmr_offset, right_shift, desc); |
620 | 620 | ||
621 | /* spin on the status MMR, waiting for it to go idle */ | 621 | /* spin on the status MMR, waiting for it to go idle */ |
622 | while (descriptor_stat != UV2H_DESC_IDLE) { | 622 | while (descriptor_stat != UV2H_DESC_IDLE) { |
@@ -658,8 +658,7 @@ static int uv2_wait_completion(struct bau_desc *bau_desc, | |||
658 | /* not to hammer on the clock */ | 658 | /* not to hammer on the clock */ |
659 | busy_reps = 0; | 659 | busy_reps = 0; |
660 | ttm = get_cycles(); | 660 | ttm = get_cycles(); |
661 | if ((ttm - bcp->send_message) > | 661 | if ((ttm - bcp->send_message) > bcp->timeout_interval) |
662 | bcp->timeout_interval) | ||
663 | return handle_uv2_busy(bcp); | 662 | return handle_uv2_busy(bcp); |
664 | } | 663 | } |
665 | /* | 664 | /* |
@@ -667,8 +666,7 @@ static int uv2_wait_completion(struct bau_desc *bau_desc, | |||
667 | */ | 666 | */ |
668 | cpu_relax(); | 667 | cpu_relax(); |
669 | } | 668 | } |
670 | descriptor_stat = uv2_read_status(mmr_offset, right_shift, | 669 | descriptor_stat = uv2_3_read_status(mmr_offset, right_shift, desc); |
671 | desc); | ||
672 | } | 670 | } |
673 | bcp->conseccompletes++; | 671 | bcp->conseccompletes++; |
674 | return FLUSH_COMPLETE; | 672 | return FLUSH_COMPLETE; |
@@ -679,8 +677,7 @@ static int uv2_wait_completion(struct bau_desc *bau_desc, | |||
679 | * which register to read and position in that register based on cpu in | 677 | * which register to read and position in that register based on cpu in |
680 | * current hub. | 678 | * current hub. |
681 | */ | 679 | */ |
682 | static int wait_completion(struct bau_desc *bau_desc, | 680 | static int wait_completion(struct bau_desc *bau_desc, struct bau_control *bcp, long try) |
683 | struct bau_control *bcp, long try) | ||
684 | { | 681 | { |
685 | int right_shift; | 682 | int right_shift; |
686 | unsigned long mmr_offset; | 683 | unsigned long mmr_offset; |
@@ -695,11 +692,9 @@ static int wait_completion(struct bau_desc *bau_desc, | |||
695 | } | 692 | } |
696 | 693 | ||
697 | if (bcp->uvhub_version == 1) | 694 | if (bcp->uvhub_version == 1) |
698 | return uv1_wait_completion(bau_desc, mmr_offset, right_shift, | 695 | return uv1_wait_completion(bau_desc, mmr_offset, right_shift, bcp, try); |
699 | bcp, try); | ||
700 | else | 696 | else |
701 | return uv2_wait_completion(bau_desc, mmr_offset, right_shift, | 697 | return uv2_3_wait_completion(bau_desc, mmr_offset, right_shift, bcp, try); |
702 | bcp, try); | ||
703 | } | 698 | } |
704 | 699 | ||
705 | /* | 700 | /* |
@@ -888,7 +883,7 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp, | |||
888 | struct ptc_stats *stat = bcp->statp; | 883 | struct ptc_stats *stat = bcp->statp; |
889 | struct bau_control *hmaster = bcp->uvhub_master; | 884 | struct bau_control *hmaster = bcp->uvhub_master; |
890 | struct uv1_bau_msg_header *uv1_hdr = NULL; | 885 | struct uv1_bau_msg_header *uv1_hdr = NULL; |
891 | struct uv2_bau_msg_header *uv2_hdr = NULL; | 886 | struct uv2_3_bau_msg_header *uv2_3_hdr = NULL; |
892 | 887 | ||
893 | if (bcp->uvhub_version == 1) { | 888 | if (bcp->uvhub_version == 1) { |
894 | uv1 = 1; | 889 | uv1 = 1; |
@@ -902,27 +897,28 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp, | |||
902 | if (uv1) | 897 | if (uv1) |
903 | uv1_hdr = &bau_desc->header.uv1_hdr; | 898 | uv1_hdr = &bau_desc->header.uv1_hdr; |
904 | else | 899 | else |
905 | uv2_hdr = &bau_desc->header.uv2_hdr; | 900 | /* uv2 and uv3 */ |
901 | uv2_3_hdr = &bau_desc->header.uv2_3_hdr; | ||
906 | 902 | ||
907 | do { | 903 | do { |
908 | if (try == 0) { | 904 | if (try == 0) { |
909 | if (uv1) | 905 | if (uv1) |
910 | uv1_hdr->msg_type = MSG_REGULAR; | 906 | uv1_hdr->msg_type = MSG_REGULAR; |
911 | else | 907 | else |
912 | uv2_hdr->msg_type = MSG_REGULAR; | 908 | uv2_3_hdr->msg_type = MSG_REGULAR; |
913 | seq_number = bcp->message_number++; | 909 | seq_number = bcp->message_number++; |
914 | } else { | 910 | } else { |
915 | if (uv1) | 911 | if (uv1) |
916 | uv1_hdr->msg_type = MSG_RETRY; | 912 | uv1_hdr->msg_type = MSG_RETRY; |
917 | else | 913 | else |
918 | uv2_hdr->msg_type = MSG_RETRY; | 914 | uv2_3_hdr->msg_type = MSG_RETRY; |
919 | stat->s_retry_messages++; | 915 | stat->s_retry_messages++; |
920 | } | 916 | } |
921 | 917 | ||
922 | if (uv1) | 918 | if (uv1) |
923 | uv1_hdr->sequence = seq_number; | 919 | uv1_hdr->sequence = seq_number; |
924 | else | 920 | else |
925 | uv2_hdr->sequence = seq_number; | 921 | uv2_3_hdr->sequence = seq_number; |
926 | index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu; | 922 | index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu; |
927 | bcp->send_message = get_cycles(); | 923 | bcp->send_message = get_cycles(); |
928 | 924 | ||
@@ -1080,8 +1076,10 @@ static int set_distrib_bits(struct cpumask *flush_mask, struct bau_control *bcp, | |||
1080 | * done. The returned pointer is valid till preemption is re-enabled. | 1076 | * done. The returned pointer is valid till preemption is re-enabled. |
1081 | */ | 1077 | */ |
1082 | const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, | 1078 | const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask, |
1083 | struct mm_struct *mm, unsigned long start, | 1079 | struct mm_struct *mm, |
1084 | unsigned long end, unsigned int cpu) | 1080 | unsigned long start, |
1081 | unsigned long end, | ||
1082 | unsigned int cpu) | ||
1085 | { | 1083 | { |
1086 | int locals = 0; | 1084 | int locals = 0; |
1087 | int remotes = 0; | 1085 | int remotes = 0; |
@@ -1268,6 +1266,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs) | |||
1268 | if (bcp->uvhub_version == 2) | 1266 | if (bcp->uvhub_version == 2) |
1269 | process_uv2_message(&msgdesc, bcp); | 1267 | process_uv2_message(&msgdesc, bcp); |
1270 | else | 1268 | else |
1269 | /* no error workaround for uv1 or uv3 */ | ||
1271 | bau_process_message(&msgdesc, bcp, 1); | 1270 | bau_process_message(&msgdesc, bcp, 1); |
1272 | 1271 | ||
1273 | msg++; | 1272 | msg++; |
@@ -1325,8 +1324,12 @@ static void __init enable_timeouts(void) | |||
1325 | */ | 1324 | */ |
1326 | mmr_image |= (1L << SOFTACK_MSHIFT); | 1325 | mmr_image |= (1L << SOFTACK_MSHIFT); |
1327 | if (is_uv2_hub()) { | 1326 | if (is_uv2_hub()) { |
1327 | /* do not touch the legacy mode bit */ | ||
1328 | /* hw bug workaround; do not use extended status */ | 1328 | /* hw bug workaround; do not use extended status */ |
1329 | mmr_image &= ~(1L << UV2_EXT_SHFT); | 1329 | mmr_image &= ~(1L << UV2_EXT_SHFT); |
1330 | } else if (is_uv3_hub()) { | ||
1331 | mmr_image &= ~(1L << PREFETCH_HINT_SHFT); | ||
1332 | mmr_image |= (1L << SB_STATUS_SHFT); | ||
1330 | } | 1333 | } |
1331 | write_mmr_misc_control(pnode, mmr_image); | 1334 | write_mmr_misc_control(pnode, mmr_image); |
1332 | } | 1335 | } |
@@ -1692,7 +1695,7 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) | |||
1692 | struct bau_desc *bau_desc; | 1695 | struct bau_desc *bau_desc; |
1693 | struct bau_desc *bd2; | 1696 | struct bau_desc *bd2; |
1694 | struct uv1_bau_msg_header *uv1_hdr; | 1697 | struct uv1_bau_msg_header *uv1_hdr; |
1695 | struct uv2_bau_msg_header *uv2_hdr; | 1698 | struct uv2_3_bau_msg_header *uv2_3_hdr; |
1696 | struct bau_control *bcp; | 1699 | struct bau_control *bcp; |
1697 | 1700 | ||
1698 | /* | 1701 | /* |
@@ -1739,15 +1742,15 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) | |||
1739 | */ | 1742 | */ |
1740 | } else { | 1743 | } else { |
1741 | /* | 1744 | /* |
1742 | * BIOS uses legacy mode, but UV2 hardware always | 1745 | * BIOS uses legacy mode, but uv2 and uv3 hardware always |
1743 | * uses native mode for selective broadcasts. | 1746 | * uses native mode for selective broadcasts. |
1744 | */ | 1747 | */ |
1745 | uv2_hdr = &bd2->header.uv2_hdr; | 1748 | uv2_3_hdr = &bd2->header.uv2_3_hdr; |
1746 | uv2_hdr->swack_flag = 1; | 1749 | uv2_3_hdr->swack_flag = 1; |
1747 | uv2_hdr->base_dest_nasid = | 1750 | uv2_3_hdr->base_dest_nasid = |
1748 | UV_PNODE_TO_NASID(base_pnode); | 1751 | UV_PNODE_TO_NASID(base_pnode); |
1749 | uv2_hdr->dest_subnodeid = UV_LB_SUBNODEID; | 1752 | uv2_3_hdr->dest_subnodeid = UV_LB_SUBNODEID; |
1750 | uv2_hdr->command = UV_NET_ENDPOINT_INTD; | 1753 | uv2_3_hdr->command = UV_NET_ENDPOINT_INTD; |
1751 | } | 1754 | } |
1752 | } | 1755 | } |
1753 | for_each_present_cpu(cpu) { | 1756 | for_each_present_cpu(cpu) { |
@@ -1858,6 +1861,7 @@ static int calculate_destination_timeout(void) | |||
1858 | ts_ns *= (mult1 * mult2); | 1861 | ts_ns *= (mult1 * mult2); |
1859 | ret = ts_ns / 1000; | 1862 | ret = ts_ns / 1000; |
1860 | } else { | 1863 | } else { |
1864 | /* same destination timeout for uv2 and uv3 */ | ||
1861 | /* 4 bits 0/1 for 10/80us base, 3 bits of multiplier */ | 1865 | /* 4 bits 0/1 for 10/80us base, 3 bits of multiplier */ |
1862 | mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL); | 1866 | mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL); |
1863 | mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT; | 1867 | mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT; |
@@ -2012,8 +2016,10 @@ static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp, | |||
2012 | bcp->uvhub_version = 1; | 2016 | bcp->uvhub_version = 1; |
2013 | else if (is_uv2_hub()) | 2017 | else if (is_uv2_hub()) |
2014 | bcp->uvhub_version = 2; | 2018 | bcp->uvhub_version = 2; |
2019 | else if (is_uv3_hub()) | ||
2020 | bcp->uvhub_version = 3; | ||
2015 | else { | 2021 | else { |
2016 | printk(KERN_EMERG "uvhub version not 1 or 2\n"); | 2022 | printk(KERN_EMERG "uvhub version not 1, 2 or 3\n"); |
2017 | return 1; | 2023 | return 1; |
2018 | } | 2024 | } |
2019 | bcp->uvhub_master = *hmasterp; | 2025 | bcp->uvhub_master = *hmasterp; |
@@ -2138,9 +2144,10 @@ static int __init uv_bau_init(void) | |||
2138 | } | 2144 | } |
2139 | 2145 | ||
2140 | vector = UV_BAU_MESSAGE; | 2146 | vector = UV_BAU_MESSAGE; |
2141 | for_each_possible_blade(uvhub) | 2147 | for_each_possible_blade(uvhub) { |
2142 | if (uv_blade_nr_possible_cpus(uvhub)) | 2148 | if (uv_blade_nr_possible_cpus(uvhub)) |
2143 | init_uvhub(uvhub, vector, uv_base_pnode); | 2149 | init_uvhub(uvhub, vector, uv_base_pnode); |
2150 | } | ||
2144 | 2151 | ||
2145 | alloc_intr_gate(vector, uv_bau_message_intr1); | 2152 | alloc_intr_gate(vector, uv_bau_message_intr1); |
2146 | 2153 | ||