1 /* 2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 /*! Functionality for symetrical multi-processors */ 12 13 14 #include <smp.h> 15 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <arch/cpu.h> 20 #include <arch/debug.h> 21 #include <arch/int.h> 22 #include <arch/smp.h> 23 #include <cpu.h> 24 #include <generic_syscall.h> 25 #include <int.h> 26 #include <spinlock_contention.h> 27 #include <thread.h> 28 #if DEBUG_SPINLOCK_LATENCIES 29 # include <safemode.h> 30 #endif 31 32 #include "kernel_debug_config.h" 33 34 35 //#define TRACE_SMP 36 #ifdef TRACE_SMP 37 # define TRACE(x) dprintf x 38 #else 39 # define TRACE(x) ; 40 #endif 41 42 43 #define MSG_POOL_SIZE (SMP_MAX_CPUS * 4) 44 45 // These macros define the number of unsuccessful iterations in 46 // acquire_spinlock() and acquire_spinlock_nocheck() after which the functions 47 // panic(), assuming a deadlock. 48 #define SPINLOCK_DEADLOCK_COUNT 100000000 49 #define SPINLOCK_DEADLOCK_COUNT_NO_CHECK 2000000000 50 51 52 struct smp_msg { 53 struct smp_msg *next; 54 int32 message; 55 uint32 data; 56 uint32 data2; 57 uint32 data3; 58 void *data_ptr; 59 uint32 flags; 60 int32 ref_count; 61 volatile bool done; 62 uint32 proc_bitmap; 63 }; 64 65 #define MAILBOX_LOCAL 1 66 #define MAILBOX_BCAST 2 67 68 static spinlock boot_cpu_spin[SMP_MAX_CPUS] = { }; 69 70 static struct smp_msg *sFreeMessages = NULL; 71 static volatile int sFreeMessageCount = 0; 72 static spinlock sFreeMessageSpinlock = B_SPINLOCK_INITIALIZER; 73 74 static struct smp_msg *sCPUMessages[SMP_MAX_CPUS] = { NULL, }; 75 static spinlock sCPUMessageSpinlock[SMP_MAX_CPUS]; 76 77 static struct smp_msg *sBroadcastMessages = NULL; 78 static spinlock sBroadcastMessageSpinlock = B_SPINLOCK_INITIALIZER; 79 80 static bool sICIEnabled = false; 81 static int32 sNumCPUs = 1; 82 83 static int32 process_pending_ici(int32 currentCPU); 84 85 86 #if DEBUG_SPINLOCKS 87 #define NUM_LAST_CALLERS 32 88 89 static struct { 90 void *caller; 91 spinlock *lock; 92 } sLastCaller[NUM_LAST_CALLERS]; 93 94 static vint32 sLastIndex = 0; 95 // Is incremented atomically. Must be % NUM_LAST_CALLERS before being used 96 // as index into sLastCaller. Note, that it has to be casted to uint32 97 // before applying the modulo operation, since otherwise after overflowing 98 // that would yield negative indices. 99 100 101 static void 102 push_lock_caller(void *caller, spinlock *lock) 103 { 104 int32 index = (uint32)atomic_add(&sLastIndex, 1) % NUM_LAST_CALLERS; 105 106 sLastCaller[index].caller = caller; 107 sLastCaller[index].lock = lock; 108 } 109 110 111 static void * 112 find_lock_caller(spinlock *lock) 113 { 114 int32 lastIndex = (uint32)sLastIndex % NUM_LAST_CALLERS; 115 116 for (int32 i = 0; i < NUM_LAST_CALLERS; i++) { 117 int32 index = (NUM_LAST_CALLERS + lastIndex - 1 - i) % NUM_LAST_CALLERS; 118 if (sLastCaller[index].lock == lock) 119 return sLastCaller[index].caller; 120 } 121 122 return NULL; 123 } 124 125 126 int 127 dump_spinlock(int argc, char** argv) 128 { 129 if (argc != 2) { 130 print_debugger_command_usage(argv[0]); 131 return 0; 132 } 133 134 uint64 address; 135 if (!evaluate_debug_expression(argv[1], &address, false)) 136 return 0; 137 138 spinlock* lock = (spinlock*)(addr_t)address; 139 kprintf("spinlock %p:\n", lock); 140 bool locked = B_SPINLOCK_IS_LOCKED(lock); 141 if (locked) { 142 kprintf(" locked from %p\n", find_lock_caller(lock)); 143 } else 144 kprintf(" not locked\n"); 145 146 return 0; 147 } 148 149 150 #endif // DEBUG_SPINLOCKS 151 152 153 #if DEBUG_SPINLOCK_LATENCIES 154 155 156 #define NUM_LATENCY_LOCKS 4 157 #define DEBUG_LATENCY 200 158 159 160 static struct { 161 spinlock *lock; 162 bigtime_t timestamp; 163 } sLatency[B_MAX_CPU_COUNT][NUM_LATENCY_LOCKS]; 164 165 static int32 sLatencyIndex[B_MAX_CPU_COUNT]; 166 static bool sEnableLatencyCheck; 167 168 169 static void 170 push_latency(spinlock* lock) 171 { 172 if (!sEnableLatencyCheck) 173 return; 174 175 int32 cpu = smp_get_current_cpu(); 176 int32 index = (++sLatencyIndex[cpu]) % NUM_LATENCY_LOCKS; 177 178 sLatency[cpu][index].lock = lock; 179 sLatency[cpu][index].timestamp = system_time(); 180 } 181 182 183 static void 184 test_latency(spinlock* lock) 185 { 186 if (!sEnableLatencyCheck) 187 return; 188 189 int32 cpu = smp_get_current_cpu(); 190 191 for (int32 i = 0; i < NUM_LATENCY_LOCKS; i++) { 192 if (sLatency[cpu][i].lock == lock) { 193 bigtime_t diff = system_time() - sLatency[cpu][i].timestamp; 194 if (diff > DEBUG_LATENCY && diff < 500000) { 195 panic("spinlock %p were held for %lld usecs (%d allowed)\n", 196 lock, diff, DEBUG_LATENCY); 197 } 198 199 sLatency[cpu][i].lock = NULL; 200 } 201 } 202 } 203 204 205 #endif // DEBUG_SPINLOCK_LATENCIES 206 207 208 int 209 dump_ici_messages(int argc, char** argv) 210 { 211 // count broadcast messages 212 int32 count = 0; 213 int32 doneCount = 0; 214 int32 unreferencedCount = 0; 215 smp_msg* message = sBroadcastMessages; 216 while (message != NULL) { 217 count++; 218 if (message->done) 219 doneCount++; 220 if (message->ref_count <= 0) 221 unreferencedCount++; 222 message = message->next; 223 } 224 225 kprintf("ICI broadcast messages: %ld, first: %p\n", count, 226 sBroadcastMessages); 227 kprintf(" done: %ld\n", doneCount); 228 kprintf(" unreferenced: %ld\n", unreferencedCount); 229 230 // count per-CPU messages 231 for (int32 i = 0; i < sNumCPUs; i++) { 232 count = 0; 233 message = sCPUMessages[i]; 234 while (message != NULL) { 235 count++; 236 message = message->next; 237 } 238 239 kprintf("CPU %ld messages: %ld, first: %p\n", i, count, 240 sCPUMessages[i]); 241 } 242 243 return 0; 244 } 245 246 247 int 248 dump_ici_message(int argc, char** argv) 249 { 250 if (argc != 2) { 251 print_debugger_command_usage(argv[0]); 252 return 0; 253 } 254 255 uint64 address; 256 if (!evaluate_debug_expression(argv[1], &address, false)) 257 return 0; 258 259 smp_msg* message = (smp_msg*)(addr_t)address; 260 kprintf("ICI message %p:\n", message); 261 kprintf(" next: %p\n", message->next); 262 kprintf(" message: %ld\n", message->message); 263 kprintf(" data: %ld\n", message->data); 264 kprintf(" data2: %ld\n", message->data2); 265 kprintf(" data3: %ld\n", message->data3); 266 kprintf(" data_ptr: %p\n", message->data_ptr); 267 kprintf(" flags: %lx\n", message->flags); 268 kprintf(" ref_count: %lx\n", message->ref_count); 269 kprintf(" done: %s\n", message->done ? "true" : "false"); 270 kprintf(" proc_bitmap: %lx\n", message->proc_bitmap); 271 272 return 0; 273 } 274 275 276 static inline void 277 process_all_pending_ici(int32 currentCPU) 278 { 279 while (process_pending_ici(currentCPU) != B_ENTRY_NOT_FOUND) 280 ; 281 } 282 283 284 void 285 acquire_spinlock(spinlock *lock) 286 { 287 #if DEBUG_SPINLOCKS 288 if (are_interrupts_enabled()) { 289 panic("acquire_spinlock: attempt to acquire lock %p with interrupts " 290 "enabled", lock); 291 } 292 #endif 293 294 if (sNumCPUs > 1) { 295 int currentCPU = smp_get_current_cpu(); 296 #if B_DEBUG_SPINLOCK_CONTENTION 297 while (atomic_add(&lock->lock, 1) != 0) 298 process_all_pending_ici(currentCPU); 299 #else 300 while (1) { 301 uint32 count = 0; 302 while (*lock != 0) { 303 if (++count == SPINLOCK_DEADLOCK_COUNT) { 304 panic("acquire_spinlock(): Failed to acquire spinlock %p " 305 "for a long time!", lock); 306 count = 0; 307 } 308 309 process_all_pending_ici(currentCPU); 310 PAUSE(); 311 } 312 if (atomic_set((int32 *)lock, 1) == 0) 313 break; 314 } 315 316 # if DEBUG_SPINLOCKS 317 push_lock_caller(arch_debug_get_caller(), lock); 318 # endif 319 #endif 320 } else { 321 #if DEBUG_SPINLOCKS 322 int32 oldValue; 323 oldValue = atomic_set((int32 *)lock, 1); 324 if (oldValue != 0) { 325 panic("acquire_spinlock: attempt to acquire lock %p twice on " 326 "non-SMP system (last caller: %p, value %ld)", lock, 327 find_lock_caller(lock), oldValue); 328 } 329 330 push_lock_caller(arch_debug_get_caller(), lock); 331 #endif 332 } 333 #if DEBUG_SPINLOCK_LATENCIES 334 push_latency(lock); 335 #endif 336 } 337 338 339 static void 340 acquire_spinlock_nocheck(spinlock *lock) 341 { 342 #if DEBUG_SPINLOCKS 343 if (are_interrupts_enabled()) { 344 panic("acquire_spinlock_nocheck: attempt to acquire lock %p with " 345 "interrupts enabled", lock); 346 } 347 #endif 348 349 if (sNumCPUs > 1) { 350 #if B_DEBUG_SPINLOCK_CONTENTION 351 while (atomic_add(&lock->lock, 1) != 0) { 352 } 353 #else 354 while (1) { 355 uint32 count = 0; 356 while (*lock != 0) { 357 if (++count == SPINLOCK_DEADLOCK_COUNT_NO_CHECK) { 358 panic("acquire_spinlock(): Failed to acquire spinlock %p " 359 "for a long time!", lock); 360 count = 0; 361 } 362 363 PAUSE(); 364 } 365 366 if (atomic_set((int32 *)lock, 1) == 0) 367 break; 368 } 369 #endif 370 } else { 371 #if DEBUG_SPINLOCKS 372 if (atomic_set((int32 *)lock, 1) != 0) { 373 panic("acquire_spinlock_nocheck: attempt to acquire lock %p twice " 374 "on non-SMP system\n", lock); 375 } 376 #endif 377 } 378 } 379 380 381 /*! Equivalent to acquire_spinlock(), save for currentCPU parameter. */ 382 static void 383 acquire_spinlock_cpu(int32 currentCPU, spinlock *lock) 384 { 385 #if DEBUG_SPINLOCKS 386 if (are_interrupts_enabled()) { 387 panic("acquire_spinlock_cpu: attempt to acquire lock %p with " 388 "interrupts enabled", lock); 389 } 390 #endif 391 392 if (sNumCPUs > 1) { 393 #if B_DEBUG_SPINLOCK_CONTENTION 394 while (atomic_add(&lock->lock, 1) != 0) 395 process_all_pending_ici(currentCPU); 396 #else 397 while (1) { 398 uint32 count = 0; 399 while (*lock != 0) { 400 if (++count == SPINLOCK_DEADLOCK_COUNT) { 401 panic("acquire_spinlock_cpu(): Failed to acquire spinlock " 402 "%p for a long time!", lock); 403 count = 0; 404 } 405 406 process_all_pending_ici(currentCPU); 407 PAUSE(); 408 } 409 if (atomic_set((int32 *)lock, 1) == 0) 410 break; 411 } 412 413 # if DEBUG_SPINLOCKS 414 push_lock_caller(arch_debug_get_caller(), lock); 415 # endif 416 #endif 417 } else { 418 #if DEBUG_SPINLOCKS 419 int32 oldValue; 420 oldValue = atomic_set((int32 *)lock, 1); 421 if (oldValue != 0) { 422 panic("acquire_spinlock_cpu(): attempt to acquire lock %p twice on " 423 "non-SMP system (last caller: %p, value %ld)", lock, 424 find_lock_caller(lock), oldValue); 425 } 426 427 push_lock_caller(arch_debug_get_caller(), lock); 428 #endif 429 } 430 } 431 432 433 void 434 release_spinlock(spinlock *lock) 435 { 436 #if DEBUG_SPINLOCK_LATENCIES 437 test_latency(lock); 438 #endif 439 440 if (sNumCPUs > 1) { 441 if (are_interrupts_enabled()) 442 panic("release_spinlock: attempt to release lock %p with interrupts enabled\n", lock); 443 #if B_DEBUG_SPINLOCK_CONTENTION 444 { 445 int32 count = atomic_set(&lock->lock, 0) - 1; 446 if (count < 0) { 447 panic("release_spinlock: lock %p was already released\n", lock); 448 } else { 449 // add to the total count -- deal with carry manually 450 if ((uint32)atomic_add(&lock->count_low, count) + count 451 < (uint32)count) { 452 atomic_add(&lock->count_high, 1); 453 } 454 } 455 } 456 #else 457 if (atomic_set((int32 *)lock, 0) != 1) 458 panic("release_spinlock: lock %p was already released\n", lock); 459 #endif 460 } else { 461 #if DEBUG_SPINLOCKS 462 if (are_interrupts_enabled()) 463 panic("release_spinlock: attempt to release lock %p with interrupts enabled\n", lock); 464 if (atomic_set((int32 *)lock, 0) != 1) 465 panic("release_spinlock: lock %p was already released\n", lock); 466 #endif 467 #if DEBUG_SPINLOCK_LATENCIES 468 test_latency(lock); 469 #endif 470 } 471 } 472 473 474 /** Finds a free message and gets it. 475 * NOTE: has side effect of disabling interrupts 476 * return value is the former interrupt state 477 */ 478 479 static cpu_status 480 find_free_message(struct smp_msg **msg) 481 { 482 cpu_status state; 483 484 TRACE(("find_free_message: entry\n")); 485 486 retry: 487 while (sFreeMessageCount <= 0) { 488 state = disable_interrupts(); 489 process_all_pending_ici(smp_get_current_cpu()); 490 restore_interrupts(state); 491 PAUSE(); 492 } 493 state = disable_interrupts(); 494 acquire_spinlock(&sFreeMessageSpinlock); 495 496 if (sFreeMessageCount <= 0) { 497 // someone grabbed one while we were getting the lock, 498 // go back to waiting for it 499 release_spinlock(&sFreeMessageSpinlock); 500 restore_interrupts(state); 501 goto retry; 502 } 503 504 *msg = sFreeMessages; 505 sFreeMessages = (*msg)->next; 506 sFreeMessageCount--; 507 508 release_spinlock(&sFreeMessageSpinlock); 509 510 TRACE(("find_free_message: returning msg %p\n", *msg)); 511 512 return state; 513 } 514 515 516 /*! Similar to find_free_message(), but expects the interrupts to be disabled 517 already. 518 */ 519 static void 520 find_free_message_interrupts_disabled(int32 currentCPU, 521 struct smp_msg** _message) 522 { 523 TRACE(("find_free_message_interrupts_disabled: entry\n")); 524 525 acquire_spinlock_cpu(currentCPU, &sFreeMessageSpinlock); 526 while (sFreeMessageCount <= 0) { 527 release_spinlock(&sFreeMessageSpinlock); 528 process_all_pending_ici(currentCPU); 529 PAUSE(); 530 acquire_spinlock_cpu(currentCPU, &sFreeMessageSpinlock); 531 } 532 533 *_message = sFreeMessages; 534 sFreeMessages = (*_message)->next; 535 sFreeMessageCount--; 536 537 release_spinlock(&sFreeMessageSpinlock); 538 539 TRACE(("find_free_message_interrupts_disabled: returning msg %p\n", 540 *_message)); 541 } 542 543 544 static void 545 return_free_message(struct smp_msg *msg) 546 { 547 TRACE(("return_free_message: returning msg %p\n", msg)); 548 549 acquire_spinlock_nocheck(&sFreeMessageSpinlock); 550 msg->next = sFreeMessages; 551 sFreeMessages = msg; 552 sFreeMessageCount++; 553 release_spinlock(&sFreeMessageSpinlock); 554 } 555 556 557 static struct smp_msg * 558 check_for_message(int currentCPU, int *source_mailbox) 559 { 560 struct smp_msg *msg; 561 562 if (!sICIEnabled) 563 return NULL; 564 565 acquire_spinlock_nocheck(&sCPUMessageSpinlock[currentCPU]); 566 msg = sCPUMessages[currentCPU]; 567 if (msg != NULL) { 568 sCPUMessages[currentCPU] = msg->next; 569 release_spinlock(&sCPUMessageSpinlock[currentCPU]); 570 TRACE((" cpu %d: found msg %p in cpu mailbox\n", currentCPU, msg)); 571 *source_mailbox = MAILBOX_LOCAL; 572 } else { 573 // try getting one from the broadcast mailbox 574 575 release_spinlock(&sCPUMessageSpinlock[currentCPU]); 576 acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); 577 578 msg = sBroadcastMessages; 579 while (msg != NULL) { 580 if (CHECK_BIT(msg->proc_bitmap, currentCPU) != 0) { 581 // we have handled this one already 582 msg = msg->next; 583 continue; 584 } 585 586 // mark it so we wont try to process this one again 587 msg->proc_bitmap = SET_BIT(msg->proc_bitmap, currentCPU); 588 *source_mailbox = MAILBOX_BCAST; 589 break; 590 } 591 release_spinlock(&sBroadcastMessageSpinlock); 592 TRACE((" cpu %d: found msg %p in broadcast mailbox\n", currentCPU, msg)); 593 } 594 return msg; 595 } 596 597 598 static void 599 finish_message_processing(int currentCPU, struct smp_msg *msg, int source_mailbox) 600 { 601 int old_refcount; 602 603 old_refcount = atomic_add(&msg->ref_count, -1); 604 if (old_refcount == 1) { 605 // we were the last one to decrement the ref_count 606 // it's our job to remove it from the list & possibly clean it up 607 struct smp_msg **mbox = NULL; 608 spinlock *spinlock = NULL; 609 610 // clean up the message from one of the mailboxes 611 switch (source_mailbox) { 612 case MAILBOX_BCAST: 613 mbox = &sBroadcastMessages; 614 spinlock = &sBroadcastMessageSpinlock; 615 break; 616 case MAILBOX_LOCAL: 617 mbox = &sCPUMessages[currentCPU]; 618 spinlock = &sCPUMessageSpinlock[currentCPU]; 619 break; 620 } 621 622 acquire_spinlock_nocheck(spinlock); 623 624 TRACE(("cleaning up message %p\n", msg)); 625 626 if (source_mailbox != MAILBOX_BCAST) { 627 // local mailbox -- the message has already been removed in 628 // check_for_message() 629 } else if (msg == *mbox) { 630 (*mbox) = msg->next; 631 } else { 632 // we need to walk to find the message in the list. 633 // we can't use any data found when previously walking through 634 // the list, since the list may have changed. But, we are guaranteed 635 // to at least have msg in it. 636 struct smp_msg *last = NULL; 637 struct smp_msg *msg1; 638 639 msg1 = *mbox; 640 while (msg1 != NULL && msg1 != msg) { 641 last = msg1; 642 msg1 = msg1->next; 643 } 644 645 // by definition, last must be something 646 if (msg1 == msg && last != NULL) 647 last->next = msg->next; 648 else 649 panic("last == NULL or msg != msg1"); 650 } 651 652 release_spinlock(spinlock); 653 654 if ((msg->flags & SMP_MSG_FLAG_FREE_ARG) != 0 && msg->data_ptr != NULL) 655 free(msg->data_ptr); 656 657 if (msg->flags & SMP_MSG_FLAG_SYNC) { 658 msg->done = true; 659 // the caller cpu should now free the message 660 } else { 661 // in the !SYNC case, we get to free the message 662 return_free_message(msg); 663 } 664 } 665 } 666 667 668 static int32 669 process_pending_ici(int32 currentCPU) 670 { 671 struct smp_msg *msg; 672 bool haltCPU = false; 673 int sourceMailbox = 0; 674 int retval = B_HANDLED_INTERRUPT; 675 676 msg = check_for_message(currentCPU, &sourceMailbox); 677 if (msg == NULL) 678 return B_ENTRY_NOT_FOUND; 679 680 TRACE((" cpu %ld message = %ld\n", currentCPU, msg->message)); 681 682 switch (msg->message) { 683 case SMP_MSG_INVALIDATE_PAGE_RANGE: 684 arch_cpu_invalidate_TLB_range((addr_t)msg->data, (addr_t)msg->data2); 685 break; 686 case SMP_MSG_INVALIDATE_PAGE_LIST: 687 arch_cpu_invalidate_TLB_list((addr_t *)msg->data, (int)msg->data2); 688 break; 689 case SMP_MSG_USER_INVALIDATE_PAGES: 690 arch_cpu_user_TLB_invalidate(); 691 break; 692 case SMP_MSG_GLOBAL_INVALIDATE_PAGES: 693 arch_cpu_global_TLB_invalidate(); 694 break; 695 case SMP_MSG_CPU_HALT: 696 haltCPU = true; 697 break; 698 case SMP_MSG_CALL_FUNCTION: 699 { 700 smp_call_func func = (smp_call_func)msg->data_ptr; 701 func(msg->data, currentCPU, msg->data2, msg->data3); 702 break; 703 } 704 case SMP_MSG_RESCHEDULE: 705 thread_get_current_thread()->cpu->invoke_scheduler = true; 706 break; 707 default: 708 dprintf("smp_intercpu_int_handler: got unknown message %ld\n", msg->message); 709 } 710 711 // finish dealing with this message, possibly removing it from the list 712 finish_message_processing(currentCPU, msg, sourceMailbox); 713 714 // special case for the halt message 715 if (haltCPU) 716 debug_trap_cpu_in_kdl(currentCPU, false); 717 718 return retval; 719 } 720 721 722 #if B_DEBUG_SPINLOCK_CONTENTION 723 724 static uint64 725 get_spinlock_counter(spinlock* lock) 726 { 727 uint32 high; 728 uint32 low; 729 do { 730 high = (uint32)atomic_get(&lock->count_high); 731 low = (uint32)atomic_get(&lock->count_low); 732 } while (high != atomic_get(&lock->count_high)); 733 734 return ((uint64)high << 32) | low; 735 } 736 737 738 static status_t 739 spinlock_contention_syscall(const char* subsystem, uint32 function, 740 void* buffer, size_t bufferSize) 741 { 742 spinlock_contention_info info; 743 744 if (function != GET_SPINLOCK_CONTENTION_INFO) 745 return B_BAD_VALUE; 746 747 if (bufferSize < sizeof(spinlock_contention_info)) 748 return B_BAD_VALUE; 749 750 info.thread_spinlock_counter = get_spinlock_counter(&gThreadSpinlock); 751 info.team_spinlock_counter = get_spinlock_counter(&gTeamSpinlock); 752 753 if (!IS_USER_ADDRESS(buffer) 754 || user_memcpy(buffer, &info, sizeof(info)) != B_OK) { 755 return B_BAD_ADDRESS; 756 } 757 758 return B_OK; 759 } 760 761 #endif // B_DEBUG_SPINLOCK_CONTENTION 762 763 764 // #pragma mark - 765 766 767 int 768 smp_intercpu_int_handler(int32 cpu) 769 { 770 TRACE(("smp_intercpu_int_handler: entry on cpu %ld\n", cpu)); 771 772 process_all_pending_ici(cpu); 773 774 TRACE(("smp_intercpu_int_handler: done\n")); 775 776 return B_HANDLED_INTERRUPT; 777 } 778 779 780 void 781 smp_send_ici(int32 targetCPU, int32 message, uint32 data, uint32 data2, uint32 data3, 782 void *data_ptr, uint32 flags) 783 { 784 struct smp_msg *msg; 785 786 TRACE(("smp_send_ici: target 0x%lx, mess 0x%lx, data 0x%lx, data2 0x%lx, data3 0x%lx, ptr %p, flags 0x%lx\n", 787 targetCPU, message, data, data2, data3, data_ptr, flags)); 788 789 if (sICIEnabled) { 790 int state; 791 int currentCPU; 792 793 // find_free_message leaves interrupts disabled 794 state = find_free_message(&msg); 795 796 currentCPU = smp_get_current_cpu(); 797 if (targetCPU == currentCPU) { 798 return_free_message(msg); 799 restore_interrupts(state); 800 return; // nope, cant do that 801 } 802 803 // set up the message 804 msg->message = message; 805 msg->data = data; 806 msg->data2 = data2; 807 msg->data3 = data3; 808 msg->data_ptr = data_ptr; 809 msg->ref_count = 1; 810 msg->flags = flags; 811 msg->done = false; 812 813 // stick it in the appropriate cpu's mailbox 814 acquire_spinlock_nocheck(&sCPUMessageSpinlock[targetCPU]); 815 msg->next = sCPUMessages[targetCPU]; 816 sCPUMessages[targetCPU] = msg; 817 release_spinlock(&sCPUMessageSpinlock[targetCPU]); 818 819 arch_smp_send_ici(targetCPU); 820 821 if (flags & SMP_MSG_FLAG_SYNC) { 822 // wait for the other cpu to finish processing it 823 // the interrupt handler will ref count it to <0 824 // if the message is sync after it has removed it from the mailbox 825 while (msg->done == false) { 826 process_all_pending_ici(currentCPU); 827 PAUSE(); 828 } 829 // for SYNC messages, it's our responsibility to put it 830 // back into the free list 831 return_free_message(msg); 832 } 833 834 restore_interrupts(state); 835 } 836 } 837 838 839 void 840 smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, uint32 data, 841 uint32 data2, uint32 data3, void *data_ptr, uint32 flags) 842 { 843 if (!sICIEnabled) 844 return; 845 846 int currentCPU = smp_get_current_cpu(); 847 cpuMask &= ~((cpu_mask_t)1 << currentCPU) 848 & (((cpu_mask_t)1 << sNumCPUs) - 1); 849 if (cpuMask == 0) { 850 panic("smp_send_multicast_ici(): 0 CPU mask"); 851 return; 852 } 853 854 // count target CPUs 855 int32 targetCPUs = 0; 856 for (int32 i = 0; i < sNumCPUs; i++) { 857 if ((cpuMask & (cpu_mask_t)1 << i) != 0) 858 targetCPUs++; 859 } 860 861 // find_free_message leaves interrupts disabled 862 struct smp_msg *msg; 863 int state = find_free_message(&msg); 864 865 msg->message = message; 866 msg->data = data; 867 msg->data2 = data2; 868 msg->data3 = data3; 869 msg->data_ptr = data_ptr; 870 msg->ref_count = targetCPUs; 871 msg->flags = flags; 872 msg->proc_bitmap = ~cpuMask; 873 msg->done = false; 874 875 // stick it in the broadcast mailbox 876 acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); 877 msg->next = sBroadcastMessages; 878 sBroadcastMessages = msg; 879 release_spinlock(&sBroadcastMessageSpinlock); 880 881 arch_smp_send_broadcast_ici(); 882 // TODO: Introduce a call that only bothers the target CPUs! 883 884 if (flags & SMP_MSG_FLAG_SYNC) { 885 // wait for the other cpus to finish processing it 886 // the interrupt handler will ref count it to <0 887 // if the message is sync after it has removed it from the mailbox 888 while (msg->done == false) { 889 process_all_pending_ici(currentCPU); 890 PAUSE(); 891 } 892 893 // for SYNC messages, it's our responsibility to put it 894 // back into the free list 895 return_free_message(msg); 896 } 897 898 restore_interrupts(state); 899 } 900 901 902 void 903 smp_send_broadcast_ici(int32 message, uint32 data, uint32 data2, uint32 data3, 904 void *data_ptr, uint32 flags) 905 { 906 struct smp_msg *msg; 907 908 TRACE(("smp_send_broadcast_ici: cpu %ld mess 0x%lx, data 0x%lx, data2 0x%lx, data3 0x%lx, ptr %p, flags 0x%lx\n", 909 smp_get_current_cpu(), message, data, data2, data3, data_ptr, flags)); 910 911 if (sICIEnabled) { 912 int state; 913 int currentCPU; 914 915 // find_free_message leaves interrupts disabled 916 state = find_free_message(&msg); 917 918 currentCPU = smp_get_current_cpu(); 919 920 msg->message = message; 921 msg->data = data; 922 msg->data2 = data2; 923 msg->data3 = data3; 924 msg->data_ptr = data_ptr; 925 msg->ref_count = sNumCPUs - 1; 926 msg->flags = flags; 927 msg->proc_bitmap = SET_BIT(0, currentCPU); 928 msg->done = false; 929 930 TRACE(("smp_send_broadcast_ici%d: inserting msg %p into broadcast mbox\n", 931 currentCPU, msg)); 932 933 // stick it in the appropriate cpu's mailbox 934 acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); 935 msg->next = sBroadcastMessages; 936 sBroadcastMessages = msg; 937 release_spinlock(&sBroadcastMessageSpinlock); 938 939 arch_smp_send_broadcast_ici(); 940 941 TRACE(("smp_send_broadcast_ici: sent interrupt\n")); 942 943 if (flags & SMP_MSG_FLAG_SYNC) { 944 // wait for the other cpus to finish processing it 945 // the interrupt handler will ref count it to <0 946 // if the message is sync after it has removed it from the mailbox 947 TRACE(("smp_send_broadcast_ici: waiting for ack\n")); 948 949 while (msg->done == false) { 950 process_all_pending_ici(currentCPU); 951 PAUSE(); 952 } 953 954 TRACE(("smp_send_broadcast_ici: returning message to free list\n")); 955 956 // for SYNC messages, it's our responsibility to put it 957 // back into the free list 958 return_free_message(msg); 959 } 960 961 restore_interrupts(state); 962 } 963 964 TRACE(("smp_send_broadcast_ici: done\n")); 965 } 966 967 968 void 969 smp_send_broadcast_ici_interrupts_disabled(int32 currentCPU, int32 message, 970 uint32 data, uint32 data2, uint32 data3, void *data_ptr, uint32 flags) 971 { 972 if (!sICIEnabled) 973 return; 974 975 TRACE(("smp_send_broadcast_ici_interrupts_disabled: cpu %ld mess 0x%lx, " 976 "data 0x%lx, data2 0x%lx, data3 0x%lx, ptr %p, flags 0x%lx\n", 977 currentCPU, message, data, data2, data3, data_ptr, flags)); 978 979 struct smp_msg *msg; 980 find_free_message_interrupts_disabled(currentCPU, &msg); 981 982 msg->message = message; 983 msg->data = data; 984 msg->data2 = data2; 985 msg->data3 = data3; 986 msg->data_ptr = data_ptr; 987 msg->ref_count = sNumCPUs - 1; 988 msg->flags = flags; 989 msg->proc_bitmap = SET_BIT(0, currentCPU); 990 msg->done = false; 991 992 TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: inserting msg %p " 993 "into broadcast mbox\n", currentCPU, msg)); 994 995 // stick it in the appropriate cpu's mailbox 996 acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); 997 msg->next = sBroadcastMessages; 998 sBroadcastMessages = msg; 999 release_spinlock(&sBroadcastMessageSpinlock); 1000 1001 arch_smp_send_broadcast_ici(); 1002 1003 TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: sent interrupt\n", 1004 currentCPU)); 1005 1006 if (flags & SMP_MSG_FLAG_SYNC) { 1007 // wait for the other cpus to finish processing it 1008 // the interrupt handler will ref count it to <0 1009 // if the message is sync after it has removed it from the mailbox 1010 TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: waiting for " 1011 "ack\n", currentCPU)); 1012 1013 while (msg->done == false) { 1014 process_all_pending_ici(currentCPU); 1015 PAUSE(); 1016 } 1017 1018 TRACE(("smp_send_broadcast_ici_interrupts_disabled %ld: returning " 1019 "message to free list\n", currentCPU)); 1020 1021 // for SYNC messages, it's our responsibility to put it 1022 // back into the free list 1023 return_free_message(msg); 1024 } 1025 1026 TRACE(("smp_send_broadcast_ici_interrupts_disabled: done\n")); 1027 } 1028 1029 1030 bool 1031 smp_trap_non_boot_cpus(int32 cpu) 1032 { 1033 if (cpu > 0) { 1034 #if B_DEBUG_SPINLOCK_CONTENTION 1035 boot_cpu_spin[cpu].lock = 1; 1036 #else 1037 boot_cpu_spin[cpu] = 1; 1038 #endif 1039 acquire_spinlock_nocheck(&boot_cpu_spin[cpu]); 1040 return false; 1041 } 1042 1043 return true; 1044 } 1045 1046 1047 void 1048 smp_wake_up_non_boot_cpus() 1049 { 1050 int i; 1051 1052 // ICIs were previously being ignored 1053 if (sNumCPUs > 1) 1054 sICIEnabled = true; 1055 1056 // resume non boot CPUs 1057 for (i = 1; i < sNumCPUs; i++) { 1058 release_spinlock(&boot_cpu_spin[i]); 1059 } 1060 } 1061 1062 /* have all cpus spin until all have run */ 1063 void 1064 smp_cpu_rendezvous(volatile uint32 *var, int current_cpu) 1065 { 1066 atomic_or((vint32*)var, 1 << current_cpu); 1067 1068 while (*var != (((uint32)1 << sNumCPUs) - 1)) 1069 PAUSE(); 1070 } 1071 1072 status_t 1073 smp_init(kernel_args *args) 1074 { 1075 TRACE(("smp_init: entry\n")); 1076 1077 #if DEBUG_SPINLOCK_LATENCIES 1078 sEnableLatencyCheck 1079 = !get_safemode_boolean(B_SAFEMODE_DISABLE_LATENCY_CHECK, false); 1080 #endif 1081 1082 #if DEBUG_SPINLOCKS 1083 add_debugger_command_etc("spinlock", &dump_spinlock, 1084 "Dump info on a spinlock", 1085 "\n" 1086 "Dumps info on a spinlock.\n", 0); 1087 #endif 1088 add_debugger_command_etc("ici", &dump_ici_messages, 1089 "Dump info on pending ICI messages", 1090 "\n" 1091 "Dumps info on pending ICI messages.\n", 0); 1092 add_debugger_command_etc("ici_message", &dump_ici_message, 1093 "Dump info on an ICI message", 1094 "\n" 1095 "Dumps info on an ICI message.\n", 0); 1096 1097 if (args->num_cpus > 1) { 1098 sFreeMessages = NULL; 1099 sFreeMessageCount = 0; 1100 for (int i = 0; i < MSG_POOL_SIZE; i++) { 1101 struct smp_msg *msg 1102 = (struct smp_msg *)malloc(sizeof(struct smp_msg)); 1103 if (msg == NULL) { 1104 panic("error creating smp mailboxes\n"); 1105 return B_ERROR; 1106 } 1107 memset(msg, 0, sizeof(struct smp_msg)); 1108 msg->next = sFreeMessages; 1109 sFreeMessages = msg; 1110 sFreeMessageCount++; 1111 } 1112 sNumCPUs = args->num_cpus; 1113 } 1114 TRACE(("smp_init: calling arch_smp_init\n")); 1115 1116 return arch_smp_init(args); 1117 } 1118 1119 1120 status_t 1121 smp_per_cpu_init(kernel_args *args, int32 cpu) 1122 { 1123 return arch_smp_per_cpu_init(args, cpu); 1124 } 1125 1126 1127 status_t 1128 smp_init_post_generic_syscalls(void) 1129 { 1130 #if B_DEBUG_SPINLOCK_CONTENTION 1131 return register_generic_syscall(SPINLOCK_CONTENTION, 1132 &spinlock_contention_syscall, 0, 0); 1133 #else 1134 return B_OK; 1135 #endif 1136 } 1137 1138 1139 void 1140 smp_set_num_cpus(int32 numCPUs) 1141 { 1142 sNumCPUs = numCPUs; 1143 } 1144 1145 1146 int32 1147 smp_get_num_cpus() 1148 { 1149 return sNumCPUs; 1150 } 1151 1152 1153 int32 1154 smp_get_current_cpu(void) 1155 { 1156 return thread_get_current_thread()->cpu->cpu_num; 1157 } 1158 1159 1160 // #pragma mark - 1161 // public exported functions 1162 1163 1164 void 1165 call_all_cpus(void (*func)(void *, int), void *cookie) 1166 { 1167 cpu_status state = disable_interrupts(); 1168 1169 if (smp_get_num_cpus() > 1) { 1170 smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (uint32)cookie, 1171 0, 0, (void *)func, SMP_MSG_FLAG_ASYNC); 1172 } 1173 1174 // we need to call this function ourselves as well 1175 func(cookie, smp_get_current_cpu()); 1176 1177 restore_interrupts(state); 1178 } 1179 1180 void 1181 call_all_cpus_sync(void (*func)(void *, int), void *cookie) 1182 { 1183 cpu_status state = disable_interrupts(); 1184 1185 if (smp_get_num_cpus() > 1) { 1186 smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (uint32)cookie, 1187 0, 0, (void *)func, SMP_MSG_FLAG_SYNC); 1188 } 1189 1190 // we need to call this function ourselves as well 1191 func(cookie, smp_get_current_cpu()); 1192 1193 restore_interrupts(state); 1194 } 1195 1196 1197 void 1198 memory_read_barrier(void) 1199 { 1200 arch_cpu_memory_read_barrier(); 1201 } 1202 1203 1204 void 1205 memory_write_barrier(void) 1206 { 1207 arch_cpu_memory_write_barrier(); 1208 } 1209 1210