diff options
-rw-r--r-- | arch/ia64/sn/kernel/bte.c | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 647deae9bfcd..7adef84190db 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c | |||
@@ -29,16 +29,30 @@ | |||
29 | 29 | ||
30 | /* two interfaces on two btes */ | 30 | /* two interfaces on two btes */ |
31 | #define MAX_INTERFACES_TO_TRY 4 | 31 | #define MAX_INTERFACES_TO_TRY 4 |
32 | #define MAX_NODES_TO_TRY 2 | ||
32 | 33 | ||
33 | static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface) | 34 | static struct bteinfo_s *bte_if_on_node(nasid_t nasid, int interface) |
34 | { | 35 | { |
35 | nodepda_t *tmp_nodepda; | 36 | nodepda_t *tmp_nodepda; |
36 | 37 | ||
38 | if (nasid_to_cnodeid(nasid) == -1) | ||
39 | return (struct bteinfo_s *)NULL;; | ||
40 | |||
37 | tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); | 41 | tmp_nodepda = NODEPDA(nasid_to_cnodeid(nasid)); |
38 | return &tmp_nodepda->bte_if[interface]; | 42 | return &tmp_nodepda->bte_if[interface]; |
39 | 43 | ||
40 | } | 44 | } |
41 | 45 | ||
46 | static inline void bte_start_transfer(struct bteinfo_s *bte, u64 len, u64 mode) | ||
47 | { | ||
48 | if (is_shub2()) { | ||
49 | BTE_CTRL_STORE(bte, (IBLS_BUSY | ((len) | (mode) << 24))); | ||
50 | } else { | ||
51 | BTE_LNSTAT_STORE(bte, len); | ||
52 | BTE_CTRL_STORE(bte, mode); | ||
53 | } | ||
54 | } | ||
55 | |||
42 | /************************************************************************ | 56 | /************************************************************************ |
43 | * Block Transfer Engine copy related functions. | 57 | * Block Transfer Engine copy related functions. |
44 | * | 58 | * |
@@ -67,13 +81,15 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) | |||
67 | { | 81 | { |
68 | u64 transfer_size; | 82 | u64 transfer_size; |
69 | u64 transfer_stat; | 83 | u64 transfer_stat; |
84 | u64 notif_phys_addr; | ||
70 | struct bteinfo_s *bte; | 85 | struct bteinfo_s *bte; |
71 | bte_result_t bte_status; | 86 | bte_result_t bte_status; |
72 | unsigned long irq_flags; | 87 | unsigned long irq_flags; |
73 | unsigned long itc_end = 0; | 88 | unsigned long itc_end = 0; |
74 | struct bteinfo_s *btes_to_try[MAX_INTERFACES_TO_TRY]; | 89 | int nasid_to_try[MAX_NODES_TO_TRY]; |
75 | int bte_if_index; | 90 | int my_nasid = get_nasid(); |
76 | int bte_pri, bte_sec; | 91 | int bte_if_index, nasid_index; |
92 | int bte_first, btes_per_node = BTES_PER_NODE; | ||
77 | 93 | ||
78 | BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", | 94 | BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", |
79 | src, dest, len, mode, notification)); | 95 | src, dest, len, mode, notification)); |
@@ -86,36 +102,26 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) | |||
86 | (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)); | 102 | (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK)); |
87 | BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT))); | 103 | BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT))); |
88 | 104 | ||
89 | /* CPU 0 (per node) tries bte0 first, CPU 1 try bte1 first */ | 105 | /* |
90 | if (cpuid_to_subnode(smp_processor_id()) == 0) { | 106 | * Start with interface corresponding to cpu number |
91 | bte_pri = 0; | 107 | */ |
92 | bte_sec = 1; | 108 | bte_first = get_cpu() % btes_per_node; |
93 | } else { | ||
94 | bte_pri = 1; | ||
95 | bte_sec = 0; | ||
96 | } | ||
97 | 109 | ||
98 | if (mode & BTE_USE_DEST) { | 110 | if (mode & BTE_USE_DEST) { |
99 | /* try remote then local */ | 111 | /* try remote then local */ |
100 | btes_to_try[0] = bte_if_on_node(NASID_GET(dest), bte_pri); | 112 | nasid_to_try[0] = NASID_GET(dest); |
101 | btes_to_try[1] = bte_if_on_node(NASID_GET(dest), bte_sec); | ||
102 | if (mode & BTE_USE_ANY) { | 113 | if (mode & BTE_USE_ANY) { |
103 | btes_to_try[2] = bte_if_on_node(get_nasid(), bte_pri); | 114 | nasid_to_try[1] = my_nasid; |
104 | btes_to_try[3] = bte_if_on_node(get_nasid(), bte_sec); | ||
105 | } else { | 115 | } else { |
106 | btes_to_try[2] = NULL; | 116 | nasid_to_try[1] = (int)NULL; |
107 | btes_to_try[3] = NULL; | ||
108 | } | 117 | } |
109 | } else { | 118 | } else { |
110 | /* try local then remote */ | 119 | /* try local then remote */ |
111 | btes_to_try[0] = bte_if_on_node(get_nasid(), bte_pri); | 120 | nasid_to_try[0] = my_nasid; |
112 | btes_to_try[1] = bte_if_on_node(get_nasid(), bte_sec); | ||
113 | if (mode & BTE_USE_ANY) { | 121 | if (mode & BTE_USE_ANY) { |
114 | btes_to_try[2] = bte_if_on_node(NASID_GET(dest), bte_pri); | 122 | nasid_to_try[1] = NASID_GET(dest); |
115 | btes_to_try[3] = bte_if_on_node(NASID_GET(dest), bte_sec); | ||
116 | } else { | 123 | } else { |
117 | btes_to_try[2] = NULL; | 124 | nasid_to_try[1] = (int)NULL; |
118 | btes_to_try[3] = NULL; | ||
119 | } | 125 | } |
120 | } | 126 | } |
121 | 127 | ||
@@ -123,11 +129,12 @@ retry_bteop: | |||
123 | do { | 129 | do { |
124 | local_irq_save(irq_flags); | 130 | local_irq_save(irq_flags); |
125 | 131 | ||
126 | bte_if_index = 0; | 132 | bte_if_index = bte_first; |
133 | nasid_index = 0; | ||
127 | 134 | ||
128 | /* Attempt to lock one of the BTE interfaces. */ | 135 | /* Attempt to lock one of the BTE interfaces. */ |
129 | while (bte_if_index < MAX_INTERFACES_TO_TRY) { | 136 | while (nasid_index < MAX_NODES_TO_TRY) { |
130 | bte = btes_to_try[bte_if_index++]; | 137 | bte = bte_if_on_node(nasid_to_try[nasid_index],bte_if_index); |
131 | 138 | ||
132 | if (bte == NULL) { | 139 | if (bte == NULL) { |
133 | continue; | 140 | continue; |
@@ -143,6 +150,15 @@ retry_bteop: | |||
143 | break; | 150 | break; |
144 | } | 151 | } |
145 | } | 152 | } |
153 | |||
154 | bte_if_index = (bte_if_index + 1) % btes_per_node; /* Next interface */ | ||
155 | if (bte_if_index == bte_first) { | ||
156 | /* | ||
157 | * We've tried all interfaces on this node | ||
158 | */ | ||
159 | nasid_index++; | ||
160 | } | ||
161 | |||
146 | bte = NULL; | 162 | bte = NULL; |
147 | } | 163 | } |
148 | 164 | ||
@@ -169,7 +185,13 @@ retry_bteop: | |||
169 | 185 | ||
170 | /* Initialize the notification to a known value. */ | 186 | /* Initialize the notification to a known value. */ |
171 | *bte->most_rcnt_na = BTE_WORD_BUSY; | 187 | *bte->most_rcnt_na = BTE_WORD_BUSY; |
188 | notif_phys_addr = TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)); | ||
172 | 189 | ||
190 | if (is_shub2()) { | ||
191 | src = SH2_TIO_PHYS_TO_DMA(src); | ||
192 | dest = SH2_TIO_PHYS_TO_DMA(dest); | ||
193 | notif_phys_addr = SH2_TIO_PHYS_TO_DMA(notif_phys_addr); | ||
194 | } | ||
173 | /* Set the source and destination registers */ | 195 | /* Set the source and destination registers */ |
174 | BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); | 196 | BTE_PRINTKV(("IBSA = 0x%lx)\n", (TO_PHYS(src)))); |
175 | BTE_SRC_STORE(bte, TO_PHYS(src)); | 197 | BTE_SRC_STORE(bte, TO_PHYS(src)); |
@@ -177,14 +199,12 @@ retry_bteop: | |||
177 | BTE_DEST_STORE(bte, TO_PHYS(dest)); | 199 | BTE_DEST_STORE(bte, TO_PHYS(dest)); |
178 | 200 | ||
179 | /* Set the notification register */ | 201 | /* Set the notification register */ |
180 | BTE_PRINTKV(("IBNA = 0x%lx)\n", | 202 | BTE_PRINTKV(("IBNA = 0x%lx)\n", notif_phys_addr)); |
181 | TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)))); | 203 | BTE_NOTIF_STORE(bte, notif_phys_addr); |
182 | BTE_NOTIF_STORE(bte, | ||
183 | TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))); | ||
184 | 204 | ||
185 | /* Initiate the transfer */ | 205 | /* Initiate the transfer */ |
186 | BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); | 206 | BTE_PRINTK(("IBCT = 0x%lx)\n", BTE_VALID_MODE(mode))); |
187 | BTE_START_TRANSFER(bte, transfer_size, BTE_VALID_MODE(mode)); | 207 | bte_start_transfer(bte, transfer_size, BTE_VALID_MODE(mode)); |
188 | 208 | ||
189 | itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); | 209 | itc_end = ia64_get_itc() + (40000000 * local_cpu_data->cyc_per_usec); |
190 | 210 | ||