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 | |
| 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>
| -rw-r--r-- | arch/x86/include/asm/uv/uv_bau.h | 19 | ||||
| -rw-r--r-- | arch/x86/platform/uv/tlb_uv.c | 69 |
2 files changed, 49 insertions, 39 deletions
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index 0b46ef261c77..2d60a7813dfe 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h | |||
| @@ -73,6 +73,7 @@ | |||
| 73 | #define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD (is_uv1_hub() ? \ | 73 | #define UV_INTD_SOFT_ACK_TIMEOUT_PERIOD (is_uv1_hub() ? \ |
| 74 | UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD : \ | 74 | UV1_INTD_SOFT_ACK_TIMEOUT_PERIOD : \ |
| 75 | UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD) | 75 | UV2_INTD_SOFT_ACK_TIMEOUT_PERIOD) |
| 76 | /* assuming UV3 is the same */ | ||
| 76 | 77 | ||
| 77 | #define BAU_MISC_CONTROL_MULT_MASK 3 | 78 | #define BAU_MISC_CONTROL_MULT_MASK 3 |
| 78 | 79 | ||
| @@ -93,6 +94,8 @@ | |||
| 93 | #define SOFTACK_MSHIFT UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT | 94 | #define SOFTACK_MSHIFT UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT |
| 94 | #define SOFTACK_PSHIFT UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT | 95 | #define SOFTACK_PSHIFT UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT |
| 95 | #define SOFTACK_TIMEOUT_PERIOD UV_INTD_SOFT_ACK_TIMEOUT_PERIOD | 96 | #define SOFTACK_TIMEOUT_PERIOD UV_INTD_SOFT_ACK_TIMEOUT_PERIOD |
| 97 | #define PREFETCH_HINT_SHFT UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_SHFT | ||
| 98 | #define SB_STATUS_SHFT UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT | ||
| 96 | #define write_gmmr uv_write_global_mmr64 | 99 | #define write_gmmr uv_write_global_mmr64 |
| 97 | #define write_lmmr uv_write_local_mmr | 100 | #define write_lmmr uv_write_local_mmr |
| 98 | #define read_lmmr uv_read_local_mmr | 101 | #define read_lmmr uv_read_local_mmr |
| @@ -322,8 +325,9 @@ struct uv1_bau_msg_header { | |||
| 322 | /* | 325 | /* |
| 323 | * UV2 Message header: 16 bytes (128 bits) (bytes 0x30-0x3f of descriptor) | 326 | * UV2 Message header: 16 bytes (128 bits) (bytes 0x30-0x3f of descriptor) |
| 324 | * see figure 9-2 of harp_sys.pdf | 327 | * see figure 9-2 of harp_sys.pdf |
| 328 | * assuming UV3 is the same | ||
| 325 | */ | 329 | */ |
| 326 | struct uv2_bau_msg_header { | 330 | struct uv2_3_bau_msg_header { |
| 327 | unsigned int base_dest_nasid:15; /* nasid of the first bit */ | 331 | unsigned int base_dest_nasid:15; /* nasid of the first bit */ |
| 328 | /* bits 14:0 */ /* in uvhub map */ | 332 | /* bits 14:0 */ /* in uvhub map */ |
| 329 | unsigned int dest_subnodeid:5; /* must be 0x10, for the LB */ | 333 | unsigned int dest_subnodeid:5; /* must be 0x10, for the LB */ |
| @@ -395,7 +399,7 @@ struct bau_desc { | |||
| 395 | */ | 399 | */ |
| 396 | union bau_msg_header { | 400 | union bau_msg_header { |
| 397 | struct uv1_bau_msg_header uv1_hdr; | 401 | struct uv1_bau_msg_header uv1_hdr; |
| 398 | struct uv2_bau_msg_header uv2_hdr; | 402 | struct uv2_3_bau_msg_header uv2_3_hdr; |
| 399 | } header; | 403 | } header; |
| 400 | 404 | ||
| 401 | struct bau_msg_payload payload; | 405 | struct bau_msg_payload payload; |
| @@ -631,11 +635,6 @@ struct bau_control { | |||
| 631 | struct hub_and_pnode *thp; | 635 | struct hub_and_pnode *thp; |
| 632 | }; | 636 | }; |
| 633 | 637 | ||
| 634 | static inline unsigned long read_mmr_uv2_status(void) | ||
| 635 | { | ||
| 636 | return read_lmmr(UV2H_LB_BAU_SB_ACTIVATION_STATUS_2); | ||
| 637 | } | ||
| 638 | |||
| 639 | static inline void write_mmr_data_broadcast(int pnode, unsigned long mmr_image) | 638 | static inline void write_mmr_data_broadcast(int pnode, unsigned long mmr_image) |
| 640 | { | 639 | { |
| 641 | write_gmmr(pnode, UVH_BAU_DATA_BROADCAST, mmr_image); | 640 | write_gmmr(pnode, UVH_BAU_DATA_BROADCAST, mmr_image); |
| @@ -760,7 +759,11 @@ static inline int atomic_read_short(const struct atomic_short *v) | |||
| 760 | */ | 759 | */ |
| 761 | static inline int atom_asr(short i, struct atomic_short *v) | 760 | static inline int atom_asr(short i, struct atomic_short *v) |
| 762 | { | 761 | { |
| 763 | return i + xadd(&v->counter, i); | 762 | short __i = i; |
| 763 | asm volatile(LOCK_PREFIX "xaddw %0, %1" | ||
| 764 | : "+r" (i), "+m" (v->counter) | ||
| 765 | : : "memory"); | ||
| 766 | return i + __i; | ||
| 764 | } | 767 | } |
| 765 | 768 | ||
| 766 | /* | 769 | /* |
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 |
