blob: d8705e97e8d06e2dcf1ae98896ec32cc1584537f [file] [log] [blame]
Cliff Wickman18129242008-06-02 08:56:14 -05001/*
2 * SGI UltraViolet TLB flush routines.
3 *
4 * (c) 2008 Cliff Wickman <cpw@sgi.com>, SGI.
5 *
6 * This code is released under the GNU General Public License version 2 or
7 * later.
8 */
9#include <linux/mc146818rtc.h>
10#include <linux/proc_fs.h>
11#include <linux/kernel.h>
12
Cliff Wickman18129242008-06-02 08:56:14 -050013#include <asm/mmu_context.h>
14#include <asm/idle.h>
15#include <asm/genapic.h>
16#include <asm/uv/uv_hub.h>
17#include <asm/uv/uv_mmrs.h>
18#include <asm/uv/uv_bau.h>
Cliff Wickmanb194b1202008-06-12 08:23:48 -050019#include <asm/tsc.h>
Cliff Wickman18129242008-06-02 08:56:14 -050020
Cliff Wickmanb194b1202008-06-12 08:23:48 -050021#include <mach_apic.h>
22
23static struct bau_control **uv_bau_table_bases __read_mostly;
24static int uv_bau_retry_limit __read_mostly;
25static int uv_nshift __read_mostly; /* position of pnode (which is nasid>>1) */
26static unsigned long uv_mmask __read_mostly;
Cliff Wickman18129242008-06-02 08:56:14 -050027
Ingo Molnardc163a42008-06-18 14:15:43 +020028static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
29static DEFINE_PER_CPU(struct bau_control, bau_control);
Cliff Wickman18129242008-06-02 08:56:14 -050030
31/*
32 * Free a software acknowledge hardware resource by clearing its Pending
33 * bit. This will return a reply to the sender.
34 * If the message has timed out, a reply has already been sent by the
35 * hardware but the resource has not been released. In that case our
36 * clear of the Timeout bit (as well) will free the resource. No reply will
37 * be sent (the hardware will only do one reply per message).
38 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -050039static void uv_reply_to_message(int resource,
Cliff Wickman18129242008-06-02 08:56:14 -050040 struct bau_payload_queue_entry *msg,
41 struct bau_msg_status *msp)
42{
Cliff Wickmanb194b1202008-06-12 08:23:48 -050043 unsigned long dw;
Cliff Wickman18129242008-06-02 08:56:14 -050044
Cliff Wickmanb194b1202008-06-12 08:23:48 -050045 dw = (1 << (resource + UV_SW_ACK_NPENDING)) | (1 << resource);
Cliff Wickman18129242008-06-02 08:56:14 -050046 msg->replied_to = 1;
47 msg->sw_ack_vector = 0;
48 if (msp)
49 msp->seen_by.bits = 0;
Cliff Wickmanb194b1202008-06-12 08:23:48 -050050 uv_write_local_mmr(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, dw);
Cliff Wickman18129242008-06-02 08:56:14 -050051}
52
53/*
54 * Do all the things a cpu should do for a TLB shootdown message.
55 * Other cpu's may come here at the same time for this message.
56 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -050057static void uv_bau_process_message(struct bau_payload_queue_entry *msg,
Cliff Wickman18129242008-06-02 08:56:14 -050058 int msg_slot, int sw_ack_slot)
59{
60 int cpu;
61 unsigned long this_cpu_mask;
62 struct bau_msg_status *msp;
63
64 msp = __get_cpu_var(bau_control).msg_statuses + msg_slot;
65 cpu = uv_blade_processor_id();
66 msg->number_of_cpus =
67 uv_blade_nr_online_cpus(uv_node_to_blade_id(numa_node_id()));
Ingo Molnardc163a42008-06-18 14:15:43 +020068 this_cpu_mask = 1UL << cpu;
Cliff Wickman18129242008-06-02 08:56:14 -050069 if (msp->seen_by.bits & this_cpu_mask)
70 return;
71 atomic_or_long(&msp->seen_by.bits, this_cpu_mask);
72
73 if (msg->replied_to == 1)
74 return;
75
76 if (msg->address == TLB_FLUSH_ALL) {
77 local_flush_tlb();
78 __get_cpu_var(ptcstats).alltlb++;
79 } else {
80 __flush_tlb_one(msg->address);
81 __get_cpu_var(ptcstats).onetlb++;
82 }
83
84 __get_cpu_var(ptcstats).requestee++;
85
86 atomic_inc_short(&msg->acknowledge_count);
87 if (msg->number_of_cpus == msg->acknowledge_count)
88 uv_reply_to_message(sw_ack_slot, msg, msp);
Ingo Molnardc163a42008-06-18 14:15:43 +020089}
90
91/*
92 * Examine the payload queue on one distribution node to see
93 * which messages have not been seen, and which cpu(s) have not seen them.
94 *
95 * Returns the number of cpu's that have not responded.
96 */
97static int uv_examine_destination(struct bau_control *bau_tablesp, int sender)
98{
99 int i;
100 int j;
101 int count = 0;
102 struct bau_payload_queue_entry *msg;
103 struct bau_msg_status *msp;
104
105 for (msg = bau_tablesp->va_queue_first, i = 0; i < DEST_Q_SIZE;
106 msg++, i++) {
107 if ((msg->sending_cpu == sender) && (!msg->replied_to)) {
108 msp = bau_tablesp->msg_statuses + i;
109 printk(KERN_DEBUG
110 "blade %d: address:%#lx %d of %d, not cpu(s): ",
111 i, msg->address, msg->acknowledge_count,
112 msg->number_of_cpus);
113 for (j = 0; j < msg->number_of_cpus; j++) {
114 if (!((long)1 << j & msp-> seen_by.bits)) {
115 count++;
116 printk("%d ", j);
117 }
118 }
119 printk("\n");
120 }
121 }
122 return count;
Cliff Wickman18129242008-06-02 08:56:14 -0500123}
124
125/*
126 * Examine the payload queue on all the distribution nodes to see
127 * which messages have not been seen, and which cpu(s) have not seen them.
128 *
129 * Returns the number of cpu's that have not responded.
130 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500131static int uv_examine_destinations(struct bau_target_nodemask *distribution)
Cliff Wickman18129242008-06-02 08:56:14 -0500132{
133 int sender;
134 int i;
Cliff Wickman18129242008-06-02 08:56:14 -0500135 int count = 0;
Cliff Wickman18129242008-06-02 08:56:14 -0500136
137 sender = smp_processor_id();
138 for (i = 0; i < (sizeof(struct bau_target_nodemask) * BITSPERBYTE);
139 i++) {
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500140 if (!bau_node_isset(i, distribution))
141 continue;
Ingo Molnardc163a42008-06-18 14:15:43 +0200142 count += uv_examine_destination(uv_bau_table_bases[i], sender);
Cliff Wickman18129242008-06-02 08:56:14 -0500143 }
144 return count;
145}
146
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500147/*
148 * wait for completion of a broadcast message
149 *
150 * return COMPLETE, RETRY or GIVEUP
151 */
Ingo Molnardc163a42008-06-18 14:15:43 +0200152static int uv_wait_completion(struct bau_desc *bau_desc,
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500153 unsigned long mmr_offset, int right_shift)
154{
155 int exams = 0;
156 long destination_timeouts = 0;
157 long source_timeouts = 0;
158 unsigned long descriptor_status;
159
160 while ((descriptor_status = (((unsigned long)
161 uv_read_local_mmr(mmr_offset) >>
162 right_shift) & UV_ACT_STATUS_MASK)) !=
163 DESC_STATUS_IDLE) {
164 if (descriptor_status == DESC_STATUS_SOURCE_TIMEOUT) {
165 source_timeouts++;
166 if (source_timeouts > SOURCE_TIMEOUT_LIMIT)
167 source_timeouts = 0;
168 __get_cpu_var(ptcstats).s_retry++;
169 return FLUSH_RETRY;
170 }
171 /*
172 * spin here looking for progress at the destinations
173 */
174 if (descriptor_status == DESC_STATUS_DESTINATION_TIMEOUT) {
175 destination_timeouts++;
176 if (destination_timeouts > DESTINATION_TIMEOUT_LIMIT) {
177 /*
178 * returns number of cpus not responding
179 */
180 if (uv_examine_destinations
181 (&bau_desc->distribution) == 0) {
182 __get_cpu_var(ptcstats).d_retry++;
183 return FLUSH_RETRY;
184 }
185 exams++;
186 if (exams >= uv_bau_retry_limit) {
187 printk(KERN_DEBUG
188 "uv_flush_tlb_others");
189 printk("giving up on cpu %d\n",
190 smp_processor_id());
191 return FLUSH_GIVEUP;
192 }
193 /*
194 * delays can hang the simulator
195 udelay(1000);
196 */
197 destination_timeouts = 0;
198 }
199 }
200 }
201 return FLUSH_COMPLETE;
202}
203
204/**
205 * uv_flush_send_and_wait
206 *
207 * Send a broadcast and wait for a broadcast message to complete.
208 *
209 * The cpumaskp mask contains the cpus the broadcast was sent to.
210 *
211 * Returns 1 if all remote flushing was done. The mask is zeroed.
212 * Returns 0 if some remote flushing remains to be done. The mask is left
213 * unchanged.
214 */
Ingo Molnardc163a42008-06-18 14:15:43 +0200215int uv_flush_send_and_wait(int cpu, int this_blade, struct bau_desc *bau_desc,
216 cpumask_t *cpumaskp)
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500217{
218 int completion_status = 0;
219 int right_shift;
220 int bit;
221 int blade;
222 int tries = 0;
223 unsigned long index;
224 unsigned long mmr_offset;
225 cycles_t time1;
226 cycles_t time2;
227
228 if (cpu < UV_CPUS_PER_ACT_STATUS) {
229 mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
230 right_shift = cpu * UV_ACT_STATUS_SIZE;
231 } else {
232 mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
233 right_shift =
234 ((cpu - UV_CPUS_PER_ACT_STATUS) * UV_ACT_STATUS_SIZE);
235 }
236 time1 = get_cycles();
237 do {
238 tries++;
Ingo Molnardc163a42008-06-18 14:15:43 +0200239 index = (1UL << UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT) |
240 cpu;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500241 uv_write_local_mmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
242 completion_status = uv_wait_completion(bau_desc, mmr_offset,
243 right_shift);
244 } while (completion_status == FLUSH_RETRY);
245 time2 = get_cycles();
246 __get_cpu_var(ptcstats).sflush += (time2 - time1);
247 if (tries > 1)
248 __get_cpu_var(ptcstats).retriesok++;
249
250 if (completion_status == FLUSH_GIVEUP) {
251 /*
252 * Cause the caller to do an IPI-style TLB shootdown on
253 * the cpu's, all of which are still in the mask.
254 */
255 __get_cpu_var(ptcstats).ptc_i++;
256 return 0;
257 }
258
259 /*
260 * Success, so clear the remote cpu's from the mask so we don't
261 * use the IPI method of shootdown on them.
262 */
263 for_each_cpu_mask(bit, *cpumaskp) {
264 blade = uv_cpu_to_blade_id(bit);
265 if (blade == this_blade)
266 continue;
267 cpu_clear(bit, *cpumaskp);
268 }
269 if (!cpus_empty(*cpumaskp))
270 return 0;
271 return 1;
272}
273
Cliff Wickman18129242008-06-02 08:56:14 -0500274/**
275 * uv_flush_tlb_others - globally purge translation cache of a virtual
276 * address or all TLB's
277 * @cpumaskp: mask of all cpu's in which the address is to be removed
278 * @mm: mm_struct containing virtual address range
279 * @va: virtual address to be removed (or TLB_FLUSH_ALL for all TLB's on cpu)
280 *
281 * This is the entry point for initiating any UV global TLB shootdown.
282 *
283 * Purges the translation caches of all specified processors of the given
284 * virtual address, or purges all TLB's on specified processors.
285 *
286 * The caller has derived the cpumaskp from the mm_struct and has subtracted
287 * the local cpu from the mask. This function is called only if there
288 * are bits set in the mask. (e.g. flush_tlb_page())
289 *
290 * The cpumaskp is converted into a nodemask of the nodes containing
291 * the cpus.
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500292 *
293 * Returns 1 if all remote flushing was done.
294 * Returns 0 if some remote flushing remains to be done.
Cliff Wickman18129242008-06-02 08:56:14 -0500295 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500296int uv_flush_tlb_others(cpumask_t *cpumaskp, struct mm_struct *mm,
297 unsigned long va)
Cliff Wickman18129242008-06-02 08:56:14 -0500298{
299 int i;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500300 int bit;
Cliff Wickman18129242008-06-02 08:56:14 -0500301 int blade;
302 int cpu;
Cliff Wickman18129242008-06-02 08:56:14 -0500303 int this_blade;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500304 int locals = 0;
Ingo Molnardc163a42008-06-18 14:15:43 +0200305 struct bau_desc *bau_desc;
Cliff Wickman18129242008-06-02 08:56:14 -0500306
307 cpu = uv_blade_processor_id();
308 this_blade = uv_numa_blade_id();
309 bau_desc = __get_cpu_var(bau_control).descriptor_base;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500310 bau_desc += UV_ITEMS_PER_DESCRIPTOR * cpu;
Cliff Wickman18129242008-06-02 08:56:14 -0500311
312 bau_nodes_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
313
314 i = 0;
315 for_each_cpu_mask(bit, *cpumaskp) {
316 blade = uv_cpu_to_blade_id(bit);
Ingo Molnardc163a42008-06-18 14:15:43 +0200317 BUG_ON(blade > (UV_DISTRIBUTION_SIZE - 1));
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500318 if (blade == this_blade) {
319 locals++;
Cliff Wickman18129242008-06-02 08:56:14 -0500320 continue;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500321 }
Cliff Wickman18129242008-06-02 08:56:14 -0500322 bau_node_set(blade, &bau_desc->distribution);
Cliff Wickman18129242008-06-02 08:56:14 -0500323 i++;
324 }
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500325 if (i == 0) {
326 /*
327 * no off_node flushing; return status for local node
328 */
329 if (locals)
330 return 0;
331 else
332 return 1;
333 }
Cliff Wickman18129242008-06-02 08:56:14 -0500334 __get_cpu_var(ptcstats).requestor++;
335 __get_cpu_var(ptcstats).ntargeted += i;
336
337 bau_desc->payload.address = va;
338 bau_desc->payload.sending_cpu = smp_processor_id();
339
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500340 return uv_flush_send_and_wait(cpu, this_blade, bau_desc, cpumaskp);
Cliff Wickman18129242008-06-02 08:56:14 -0500341}
342
343/*
344 * The BAU message interrupt comes here. (registered by set_intr_gate)
345 * See entry_64.S
346 *
347 * We received a broadcast assist message.
348 *
349 * Interrupts may have been disabled; this interrupt could represent
350 * the receipt of several messages.
351 *
352 * All cores/threads on this node get this interrupt.
353 * The last one to see it does the s/w ack.
354 * (the resource will not be freed until noninterruptable cpus see this
355 * interrupt; hardware will timeout the s/w ack and reply ERROR)
356 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500357void uv_bau_message_interrupt(struct pt_regs *regs)
Cliff Wickman18129242008-06-02 08:56:14 -0500358{
359 struct bau_payload_queue_entry *pqp;
360 struct bau_payload_queue_entry *msg;
Ingo Molnardc163a42008-06-18 14:15:43 +0200361 struct bau_payload_queue_entry *va_queue_first;
362 struct bau_payload_queue_entry *va_queue_last;
Cliff Wickman18129242008-06-02 08:56:14 -0500363 struct pt_regs *old_regs = set_irq_regs(regs);
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500364 cycles_t time1, time2;
Cliff Wickman18129242008-06-02 08:56:14 -0500365 int msg_slot;
366 int sw_ack_slot;
367 int fw;
368 int count = 0;
369 unsigned long local_pnode;
370
371 ack_APIC_irq();
372 exit_idle();
373 irq_enter();
374
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500375 time1 = get_cycles();
Cliff Wickman18129242008-06-02 08:56:14 -0500376
377 local_pnode = uv_blade_to_pnode(uv_numa_blade_id());
378
Ingo Molnardc163a42008-06-18 14:15:43 +0200379 pqp = va_queue_first = __get_cpu_var(bau_control).va_queue_first;
380 va_queue_last = __get_cpu_var(bau_control).va_queue_last;
Cliff Wickman18129242008-06-02 08:56:14 -0500381 msg = __get_cpu_var(bau_control).bau_msg_head;
382 while (msg->sw_ack_vector) {
383 count++;
384 fw = msg->sw_ack_vector;
385 msg_slot = msg - pqp;
386 sw_ack_slot = ffs(fw) - 1;
387
388 uv_bau_process_message(msg, msg_slot, sw_ack_slot);
389
390 msg++;
Ingo Molnardc163a42008-06-18 14:15:43 +0200391 if (msg > va_queue_last)
392 msg = va_queue_first;
Cliff Wickman18129242008-06-02 08:56:14 -0500393 __get_cpu_var(bau_control).bau_msg_head = msg;
394 }
395 if (!count)
396 __get_cpu_var(ptcstats).nomsg++;
397 else if (count > 1)
398 __get_cpu_var(ptcstats).multmsg++;
399
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500400 time2 = get_cycles();
401 __get_cpu_var(ptcstats).dflush += (time2 - time1);
Cliff Wickman18129242008-06-02 08:56:14 -0500402
403 irq_exit();
404 set_irq_regs(old_regs);
Cliff Wickman18129242008-06-02 08:56:14 -0500405}
406
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500407static void uv_enable_timeouts(void)
Cliff Wickman18129242008-06-02 08:56:14 -0500408{
409 int i;
410 int blade;
411 int last_blade;
412 int pnode;
413 int cur_cpu = 0;
414 unsigned long apicid;
415
Cliff Wickman18129242008-06-02 08:56:14 -0500416 last_blade = -1;
417 for_each_online_node(i) {
418 blade = uv_node_to_blade_id(i);
419 if (blade == last_blade)
420 continue;
421 last_blade = blade;
422 apicid = per_cpu(x86_cpu_to_apicid, cur_cpu);
423 pnode = uv_blade_to_pnode(blade);
424 cur_cpu += uv_blade_nr_possible_cpus(i);
425 }
Cliff Wickman18129242008-06-02 08:56:14 -0500426}
427
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500428static void *uv_ptc_seq_start(struct seq_file *file, loff_t *offset)
Cliff Wickman18129242008-06-02 08:56:14 -0500429{
430 if (*offset < num_possible_cpus())
431 return offset;
432 return NULL;
433}
434
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500435static void *uv_ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
Cliff Wickman18129242008-06-02 08:56:14 -0500436{
437 (*offset)++;
438 if (*offset < num_possible_cpus())
439 return offset;
440 return NULL;
441}
442
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500443static void uv_ptc_seq_stop(struct seq_file *file, void *data)
Cliff Wickman18129242008-06-02 08:56:14 -0500444{
445}
446
447/*
448 * Display the statistics thru /proc
449 * data points to the cpu number
450 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500451static int uv_ptc_seq_show(struct seq_file *file, void *data)
Cliff Wickman18129242008-06-02 08:56:14 -0500452{
453 struct ptc_stats *stat;
454 int cpu;
455
456 cpu = *(loff_t *)data;
457
458 if (!cpu) {
459 seq_printf(file,
460 "# cpu requestor requestee one all sretry dretry ptc_i ");
461 seq_printf(file,
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500462 "sw_ack sflush dflush sok dnomsg dmult starget\n");
Cliff Wickman18129242008-06-02 08:56:14 -0500463 }
464 if (cpu < num_possible_cpus() && cpu_online(cpu)) {
465 stat = &per_cpu(ptcstats, cpu);
466 seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld ",
467 cpu, stat->requestor,
468 stat->requestee, stat->onetlb, stat->alltlb,
469 stat->s_retry, stat->d_retry, stat->ptc_i);
470 seq_printf(file, "%lx %ld %ld %ld %ld %ld %ld\n",
471 uv_read_global_mmr64(uv_blade_to_pnode
472 (uv_cpu_to_blade_id(cpu)),
473 UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE),
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500474 stat->sflush, stat->dflush,
Cliff Wickman18129242008-06-02 08:56:14 -0500475 stat->retriesok, stat->nomsg,
476 stat->multmsg, stat->ntargeted);
477 }
478
479 return 0;
480}
481
482/*
483 * 0: display meaning of the statistics
484 * >0: retry limit
485 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500486static ssize_t uv_ptc_proc_write(struct file *file, const char __user *user,
Cliff Wickman18129242008-06-02 08:56:14 -0500487 size_t count, loff_t *data)
488{
489 long newmode;
490 char optstr[64];
491
492 if (copy_from_user(optstr, user, count))
493 return -EFAULT;
494 optstr[count - 1] = '\0';
495 if (strict_strtoul(optstr, 10, &newmode) < 0) {
496 printk(KERN_DEBUG "%s is invalid\n", optstr);
497 return -EINVAL;
498 }
499
500 if (newmode == 0) {
501 printk(KERN_DEBUG "# cpu: cpu number\n");
502 printk(KERN_DEBUG
503 "requestor: times this cpu was the flush requestor\n");
504 printk(KERN_DEBUG
505 "requestee: times this cpu was requested to flush its TLBs\n");
506 printk(KERN_DEBUG
507 "one: times requested to flush a single address\n");
508 printk(KERN_DEBUG
509 "all: times requested to flush all TLB's\n");
510 printk(KERN_DEBUG
511 "sretry: number of retries of source-side timeouts\n");
512 printk(KERN_DEBUG
513 "dretry: number of retries of destination-side timeouts\n");
514 printk(KERN_DEBUG
515 "ptc_i: times UV fell through to IPI-style flushes\n");
516 printk(KERN_DEBUG
517 "sw_ack: image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE\n");
518 printk(KERN_DEBUG
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500519 "sflush_us: cycles spent in uv_flush_tlb_others()\n");
Cliff Wickman18129242008-06-02 08:56:14 -0500520 printk(KERN_DEBUG
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500521 "dflush_us: cycles spent in handling flush requests\n");
Cliff Wickman18129242008-06-02 08:56:14 -0500522 printk(KERN_DEBUG "sok: successes on retry\n");
523 printk(KERN_DEBUG "dnomsg: interrupts with no message\n");
524 printk(KERN_DEBUG
525 "dmult: interrupts with multiple messages\n");
526 printk(KERN_DEBUG "starget: nodes targeted\n");
527 } else {
528 uv_bau_retry_limit = newmode;
529 printk(KERN_DEBUG "timeout retry limit:%d\n",
530 uv_bau_retry_limit);
531 }
532
533 return count;
534}
535
536static const struct seq_operations uv_ptc_seq_ops = {
Ingo Molnardc163a42008-06-18 14:15:43 +0200537 .start = uv_ptc_seq_start,
538 .next = uv_ptc_seq_next,
539 .stop = uv_ptc_seq_stop,
540 .show = uv_ptc_seq_show
Cliff Wickman18129242008-06-02 08:56:14 -0500541};
542
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500543static int uv_ptc_proc_open(struct inode *inode, struct file *file)
Cliff Wickman18129242008-06-02 08:56:14 -0500544{
545 return seq_open(file, &uv_ptc_seq_ops);
546}
547
548static const struct file_operations proc_uv_ptc_operations = {
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500549 .open = uv_ptc_proc_open,
550 .read = seq_read,
551 .write = uv_ptc_proc_write,
552 .llseek = seq_lseek,
553 .release = seq_release,
Cliff Wickman18129242008-06-02 08:56:14 -0500554};
555
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500556static int __init uv_ptc_init(void)
Cliff Wickman18129242008-06-02 08:56:14 -0500557{
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500558 struct proc_dir_entry *proc_uv_ptc;
Cliff Wickman18129242008-06-02 08:56:14 -0500559
560 if (!is_uv_system())
561 return 0;
562
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500563 if (!proc_mkdir("sgi_uv", NULL))
Cliff Wickman18129242008-06-02 08:56:14 -0500564 return -EINVAL;
565
566 proc_uv_ptc = create_proc_entry(UV_PTC_BASENAME, 0444, NULL);
567 if (!proc_uv_ptc) {
568 printk(KERN_ERR "unable to create %s proc entry\n",
569 UV_PTC_BASENAME);
Ingo Molnardc163a42008-06-18 14:15:43 +0200570 remove_proc_entry("sgi_uv", NULL);
Cliff Wickman18129242008-06-02 08:56:14 -0500571 return -EINVAL;
572 }
573 proc_uv_ptc->proc_fops = &proc_uv_ptc_operations;
574 return 0;
575}
576
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500577/*
578 * begin the initialization of the per-blade control structures
579 */
580static struct bau_control * __init uv_table_bases_init(int blade, int node)
Cliff Wickman18129242008-06-02 08:56:14 -0500581{
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500582 int i;
583 int *ip;
584 struct bau_msg_status *msp;
Ingo Molnardc163a42008-06-18 14:15:43 +0200585 struct bau_control *bau_tabp;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500586
Ingo Molnardc163a42008-06-18 14:15:43 +0200587 bau_tabp =
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500588 kmalloc_node(sizeof(struct bau_control), GFP_KERNEL, node);
Ingo Molnardc163a42008-06-18 14:15:43 +0200589 BUG_ON(!bau_tabp);
590 bau_tabp->msg_statuses =
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500591 kmalloc_node(sizeof(struct bau_msg_status) *
Ingo Molnardc163a42008-06-18 14:15:43 +0200592 DEST_Q_SIZE, GFP_KERNEL, node);
593 BUG_ON(!bau_tabp->msg_statuses);
594 for (i = 0, msp = bau_tabp->msg_statuses; i < DEST_Q_SIZE; i++, msp++)
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500595 bau_cpubits_clear(&msp->seen_by, (int)
596 uv_blade_nr_possible_cpus(blade));
Ingo Molnardc163a42008-06-18 14:15:43 +0200597 bau_tabp->watching =
598 kmalloc_node(sizeof(int) * DEST_NUM_RESOURCES, GFP_KERNEL, node);
599 BUG_ON(!bau_tabp->watching);
600 for (i = 0, ip = bau_tabp->watching; i < DEST_Q_SIZE; i++, ip++) {
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500601 *ip = 0;
602 }
Ingo Molnardc163a42008-06-18 14:15:43 +0200603 uv_bau_table_bases[blade] = bau_tabp;
604 return bau_tabsp;
Cliff Wickman18129242008-06-02 08:56:14 -0500605}
606
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500607/*
608 * finish the initialization of the per-blade control structures
609 */
610static void __init uv_table_bases_finish(int blade, int node, int cur_cpu,
611 struct bau_control *bau_tablesp,
Ingo Molnardc163a42008-06-18 14:15:43 +0200612 struct bau_desc *adp)
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500613{
614 int i;
615 struct bau_control *bcp;
616
617 for (i = cur_cpu; i < (cur_cpu + uv_blade_nr_possible_cpus(blade));
618 i++) {
619 bcp = (struct bau_control *)&per_cpu(bau_control, i);
620 bcp->bau_msg_head = bau_tablesp->va_queue_first;
621 bcp->va_queue_first = bau_tablesp->va_queue_first;
622 bcp->va_queue_last = bau_tablesp->va_queue_last;
623 bcp->watching = bau_tablesp->watching;
624 bcp->msg_statuses = bau_tablesp->msg_statuses;
625 bcp->descriptor_base = adp;
626 }
627}
628
629/*
630 * initialize the sending side's sending buffers
631 */
Ingo Molnardc163a42008-06-18 14:15:43 +0200632static struct bau_desc * __init
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500633uv_activation_descriptor_init(int node, int pnode)
634{
635 int i;
636 unsigned long pa;
637 unsigned long m;
638 unsigned long n;
639 unsigned long mmr_image;
Ingo Molnardc163a42008-06-18 14:15:43 +0200640 struct bau_desc *adp;
641 struct bau_desc *ad2;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500642
Ingo Molnardc163a42008-06-18 14:15:43 +0200643 adp = (struct bau_desc *)
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500644 kmalloc_node(16384, GFP_KERNEL, node);
Ingo Molnardc163a42008-06-18 14:15:43 +0200645 BUG_ON(!adp);
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500646 pa = __pa((unsigned long)adp);
647 n = pa >> uv_nshift;
648 m = pa & uv_mmask;
649 mmr_image = uv_read_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE);
650 if (mmr_image)
651 uv_write_global_mmr64(pnode, (unsigned long)
652 UVH_LB_BAU_SB_DESCRIPTOR_BASE,
653 (n << UV_DESC_BASE_PNODE_SHIFT | m));
654 for (i = 0, ad2 = adp; i < UV_ACTIVATION_DESCRIPTOR_SIZE; i++, ad2++) {
Ingo Molnardc163a42008-06-18 14:15:43 +0200655 memset(ad2, 0, sizeof(struct bau_desc));
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500656 ad2->header.sw_ack_flag = 1;
657 ad2->header.base_dest_nodeid =
658 uv_blade_to_pnode(uv_cpu_to_blade_id(0));
659 ad2->header.command = UV_NET_ENDPOINT_INTD;
660 ad2->header.int_both = 1;
661 /*
662 * all others need to be set to zero:
663 * fairness chaining multilevel count replied_to
664 */
665 }
666 return adp;
667}
668
669/*
670 * initialize the destination side's receiving buffers
671 */
672static struct bau_payload_queue_entry * __init uv_payload_queue_init(int node,
673 int pnode, struct bau_control *bau_tablesp)
674{
675 char *cp;
676 struct bau_payload_queue_entry *pqp;
677
Ingo Molnardc163a42008-06-18 14:15:43 +0200678 pqp = (struct bau_payload_queue_entry *) kmalloc_node(
679 (DEST_Q_SIZE + 1) * sizeof(struct bau_payload_queue_entry),
680 GFP_KERNEL, node);
681 BUG_ON(!pqp);
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500682 cp = (char *)pqp + 31;
683 pqp = (struct bau_payload_queue_entry *)(((unsigned long)cp >> 5) << 5);
684 bau_tablesp->va_queue_first = pqp;
685 uv_write_global_mmr64(pnode,
686 UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST,
687 ((unsigned long)pnode <<
688 UV_PAYLOADQ_PNODE_SHIFT) |
689 uv_physnodeaddr(pqp));
690 uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL,
691 uv_physnodeaddr(pqp));
Ingo Molnardc163a42008-06-18 14:15:43 +0200692 bau_tablesp->va_queue_last = pqp + (DEST_Q_SIZE - 1);
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500693 uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST,
694 (unsigned long)
695 uv_physnodeaddr(bau_tablesp->va_queue_last));
Ingo Molnardc163a42008-06-18 14:15:43 +0200696 memset(pqp, 0, sizeof(struct bau_payload_queue_entry) * DEST_Q_SIZE);
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500697 return pqp;
698}
699
700/*
701 * Initialization of each UV blade's structures
702 */
703static int __init uv_init_blade(int blade, int node, int cur_cpu)
704{
705 int pnode;
706 unsigned long pa;
707 unsigned long apicid;
Ingo Molnardc163a42008-06-18 14:15:43 +0200708 struct bau_desc *adp;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500709 struct bau_payload_queue_entry *pqp;
710 struct bau_control *bau_tablesp;
711
712 bau_tablesp = uv_table_bases_init(blade, node);
713 pnode = uv_blade_to_pnode(blade);
714 adp = uv_activation_descriptor_init(node, pnode);
715 pqp = uv_payload_queue_init(node, pnode, bau_tablesp);
716 uv_table_bases_finish(blade, node, cur_cpu, bau_tablesp, adp);
717 /*
718 * the below initialization can't be in firmware because the
719 * messaging IRQ will be determined by the OS
720 */
721 apicid = per_cpu(x86_cpu_to_apicid, cur_cpu);
722 pa = uv_read_global_mmr64(pnode, UVH_BAU_DATA_CONFIG);
723 if ((pa & 0xff) != UV_BAU_MESSAGE) {
724 uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
725 ((apicid << 32) | UV_BAU_MESSAGE));
726 }
727 return 0;
728}
Cliff Wickman18129242008-06-02 08:56:14 -0500729
730/*
731 * Initialization of BAU-related structures
732 */
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500733static int __init uv_bau_init(void)
Cliff Wickman18129242008-06-02 08:56:14 -0500734{
Cliff Wickman18129242008-06-02 08:56:14 -0500735 int blade;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500736 int node;
Cliff Wickman18129242008-06-02 08:56:14 -0500737 int nblades;
Cliff Wickman18129242008-06-02 08:56:14 -0500738 int last_blade;
739 int cur_cpu = 0;
Cliff Wickman18129242008-06-02 08:56:14 -0500740
741 if (!is_uv_system())
742 return 0;
743
744 uv_bau_retry_limit = 1;
Cliff Wickman18129242008-06-02 08:56:14 -0500745 uv_nshift = uv_hub_info->n_val;
Ingo Molnardc163a42008-06-18 14:15:43 +0200746 uv_mmask = (1UL << uv_hub_info->n_val) - 1;
Cliff Wickman18129242008-06-02 08:56:14 -0500747 nblades = 0;
748 last_blade = -1;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500749 for_each_online_node(node) {
750 blade = uv_node_to_blade_id(node);
Cliff Wickman18129242008-06-02 08:56:14 -0500751 if (blade == last_blade)
752 continue;
753 last_blade = blade;
754 nblades++;
755 }
Cliff Wickman18129242008-06-02 08:56:14 -0500756 uv_bau_table_bases = (struct bau_control **)
757 kmalloc(nblades * sizeof(struct bau_control *), GFP_KERNEL);
Ingo Molnardc163a42008-06-18 14:15:43 +0200758 BUG_ON(!uv_bau_table_bases);
Cliff Wickman18129242008-06-02 08:56:14 -0500759 last_blade = -1;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500760 for_each_online_node(node) {
761 blade = uv_node_to_blade_id(node);
Cliff Wickman18129242008-06-02 08:56:14 -0500762 if (blade == last_blade)
763 continue;
764 last_blade = blade;
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500765 uv_init_blade(blade, node, cur_cpu);
766 cur_cpu += uv_blade_nr_possible_cpus(blade);
Cliff Wickman18129242008-06-02 08:56:14 -0500767 }
Cliff Wickman18129242008-06-02 08:56:14 -0500768 set_intr_gate(UV_BAU_MESSAGE, uv_bau_message_intr1);
Cliff Wickman18129242008-06-02 08:56:14 -0500769 uv_enable_timeouts();
Cliff Wickman18129242008-06-02 08:56:14 -0500770 return 0;
771}
Cliff Wickman18129242008-06-02 08:56:14 -0500772__initcall(uv_bau_init);
Cliff Wickmanb194b1202008-06-12 08:23:48 -0500773__initcall(uv_ptc_init);