diff options
Diffstat (limited to 'arch/i386/kernel/smp.c')
-rw-r--r-- | arch/i386/kernel/smp.c | 304 |
1 files changed, 166 insertions, 138 deletions
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 0e8977871b1f..89a45a9ddcd4 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c | |||
@@ -165,20 +165,20 @@ void fastcall send_IPI_self(int vector) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | /* | 167 | /* |
168 | * This is only used on smaller machines. | 168 | * This is used to send an IPI with no shorthand notation (the destination is |
169 | * specified in bits 56 to 63 of the ICR). | ||
169 | */ | 170 | */ |
170 | void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) | 171 | static inline void __send_IPI_dest_field(unsigned long mask, int vector) |
171 | { | 172 | { |
172 | unsigned long mask = cpus_addr(cpumask)[0]; | ||
173 | unsigned long cfg; | 173 | unsigned long cfg; |
174 | unsigned long flags; | ||
175 | 174 | ||
176 | local_irq_save(flags); | ||
177 | WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); | ||
178 | /* | 175 | /* |
179 | * Wait for idle. | 176 | * Wait for idle. |
180 | */ | 177 | */ |
181 | apic_wait_icr_idle(); | 178 | if (unlikely(vector == NMI_VECTOR)) |
179 | safe_apic_wait_icr_idle(); | ||
180 | else | ||
181 | apic_wait_icr_idle(); | ||
182 | 182 | ||
183 | /* | 183 | /* |
184 | * prepare target chip field | 184 | * prepare target chip field |
@@ -195,13 +195,25 @@ void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) | |||
195 | * Send the IPI. The write to APIC_ICR fires this off. | 195 | * Send the IPI. The write to APIC_ICR fires this off. |
196 | */ | 196 | */ |
197 | apic_write_around(APIC_ICR, cfg); | 197 | apic_write_around(APIC_ICR, cfg); |
198 | } | ||
199 | |||
200 | /* | ||
201 | * This is only used on smaller machines. | ||
202 | */ | ||
203 | void send_IPI_mask_bitmask(cpumask_t cpumask, int vector) | ||
204 | { | ||
205 | unsigned long mask = cpus_addr(cpumask)[0]; | ||
206 | unsigned long flags; | ||
198 | 207 | ||
208 | local_irq_save(flags); | ||
209 | WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); | ||
210 | __send_IPI_dest_field(mask, vector); | ||
199 | local_irq_restore(flags); | 211 | local_irq_restore(flags); |
200 | } | 212 | } |
201 | 213 | ||
202 | void send_IPI_mask_sequence(cpumask_t mask, int vector) | 214 | void send_IPI_mask_sequence(cpumask_t mask, int vector) |
203 | { | 215 | { |
204 | unsigned long cfg, flags; | 216 | unsigned long flags; |
205 | unsigned int query_cpu; | 217 | unsigned int query_cpu; |
206 | 218 | ||
207 | /* | 219 | /* |
@@ -211,30 +223,10 @@ void send_IPI_mask_sequence(cpumask_t mask, int vector) | |||
211 | */ | 223 | */ |
212 | 224 | ||
213 | local_irq_save(flags); | 225 | local_irq_save(flags); |
214 | |||
215 | for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) { | 226 | for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) { |
216 | if (cpu_isset(query_cpu, mask)) { | 227 | if (cpu_isset(query_cpu, mask)) { |
217 | 228 | __send_IPI_dest_field(cpu_to_logical_apicid(query_cpu), | |
218 | /* | 229 | vector); |
219 | * Wait for idle. | ||
220 | */ | ||
221 | apic_wait_icr_idle(); | ||
222 | |||
223 | /* | ||
224 | * prepare target chip field | ||
225 | */ | ||
226 | cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu)); | ||
227 | apic_write_around(APIC_ICR2, cfg); | ||
228 | |||
229 | /* | ||
230 | * program the ICR | ||
231 | */ | ||
232 | cfg = __prepare_ICR(0, vector); | ||
233 | |||
234 | /* | ||
235 | * Send the IPI. The write to APIC_ICR fires this off. | ||
236 | */ | ||
237 | apic_write_around(APIC_ICR, cfg); | ||
238 | } | 230 | } |
239 | } | 231 | } |
240 | local_irq_restore(flags); | 232 | local_irq_restore(flags); |
@@ -256,7 +248,6 @@ static cpumask_t flush_cpumask; | |||
256 | static struct mm_struct * flush_mm; | 248 | static struct mm_struct * flush_mm; |
257 | static unsigned long flush_va; | 249 | static unsigned long flush_va; |
258 | static DEFINE_SPINLOCK(tlbstate_lock); | 250 | static DEFINE_SPINLOCK(tlbstate_lock); |
259 | #define FLUSH_ALL 0xffffffff | ||
260 | 251 | ||
261 | /* | 252 | /* |
262 | * We cannot call mmdrop() because we are in interrupt context, | 253 | * We cannot call mmdrop() because we are in interrupt context, |
@@ -338,7 +329,7 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs) | |||
338 | 329 | ||
339 | if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { | 330 | if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) { |
340 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { | 331 | if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) { |
341 | if (flush_va == FLUSH_ALL) | 332 | if (flush_va == TLB_FLUSH_ALL) |
342 | local_flush_tlb(); | 333 | local_flush_tlb(); |
343 | else | 334 | else |
344 | __flush_tlb_one(flush_va); | 335 | __flush_tlb_one(flush_va); |
@@ -353,9 +344,11 @@ out: | |||
353 | put_cpu_no_resched(); | 344 | put_cpu_no_resched(); |
354 | } | 345 | } |
355 | 346 | ||
356 | static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | 347 | void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm, |
357 | unsigned long va) | 348 | unsigned long va) |
358 | { | 349 | { |
350 | cpumask_t cpumask = *cpumaskp; | ||
351 | |||
359 | /* | 352 | /* |
360 | * A couple of (to be removed) sanity checks: | 353 | * A couple of (to be removed) sanity checks: |
361 | * | 354 | * |
@@ -366,10 +359,12 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | |||
366 | BUG_ON(cpu_isset(smp_processor_id(), cpumask)); | 359 | BUG_ON(cpu_isset(smp_processor_id(), cpumask)); |
367 | BUG_ON(!mm); | 360 | BUG_ON(!mm); |
368 | 361 | ||
362 | #ifdef CONFIG_HOTPLUG_CPU | ||
369 | /* If a CPU which we ran on has gone down, OK. */ | 363 | /* If a CPU which we ran on has gone down, OK. */ |
370 | cpus_and(cpumask, cpumask, cpu_online_map); | 364 | cpus_and(cpumask, cpumask, cpu_online_map); |
371 | if (cpus_empty(cpumask)) | 365 | if (unlikely(cpus_empty(cpumask))) |
372 | return; | 366 | return; |
367 | #endif | ||
373 | 368 | ||
374 | /* | 369 | /* |
375 | * i'm not happy about this global shared spinlock in the | 370 | * i'm not happy about this global shared spinlock in the |
@@ -380,17 +375,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, | |||
380 | 375 | ||
381 | flush_mm = mm; | 376 | flush_mm = mm; |
382 | flush_va = va; | 377 | flush_va = va; |
383 | #if NR_CPUS <= BITS_PER_LONG | 378 | cpus_or(flush_cpumask, cpumask, flush_cpumask); |
384 | atomic_set_mask(cpumask, &flush_cpumask); | ||
385 | #else | ||
386 | { | ||
387 | int k; | ||
388 | unsigned long *flush_mask = (unsigned long *)&flush_cpumask; | ||
389 | unsigned long *cpu_mask = (unsigned long *)&cpumask; | ||
390 | for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k) | ||
391 | atomic_set_mask(cpu_mask[k], &flush_mask[k]); | ||
392 | } | ||
393 | #endif | ||
394 | /* | 379 | /* |
395 | * We have to send the IPI only to | 380 | * We have to send the IPI only to |
396 | * CPUs affected. | 381 | * CPUs affected. |
@@ -417,7 +402,7 @@ void flush_tlb_current_task(void) | |||
417 | 402 | ||
418 | local_flush_tlb(); | 403 | local_flush_tlb(); |
419 | if (!cpus_empty(cpu_mask)) | 404 | if (!cpus_empty(cpu_mask)) |
420 | flush_tlb_others(cpu_mask, mm, FLUSH_ALL); | 405 | flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); |
421 | preempt_enable(); | 406 | preempt_enable(); |
422 | } | 407 | } |
423 | 408 | ||
@@ -436,7 +421,7 @@ void flush_tlb_mm (struct mm_struct * mm) | |||
436 | leave_mm(smp_processor_id()); | 421 | leave_mm(smp_processor_id()); |
437 | } | 422 | } |
438 | if (!cpus_empty(cpu_mask)) | 423 | if (!cpus_empty(cpu_mask)) |
439 | flush_tlb_others(cpu_mask, mm, FLUSH_ALL); | 424 | flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL); |
440 | 425 | ||
441 | preempt_enable(); | 426 | preempt_enable(); |
442 | } | 427 | } |
@@ -483,7 +468,7 @@ void flush_tlb_all(void) | |||
483 | * it goes straight through and wastes no time serializing | 468 | * it goes straight through and wastes no time serializing |
484 | * anything. Worst case is that we lose a reschedule ... | 469 | * anything. Worst case is that we lose a reschedule ... |
485 | */ | 470 | */ |
486 | void smp_send_reschedule(int cpu) | 471 | void native_smp_send_reschedule(int cpu) |
487 | { | 472 | { |
488 | WARN_ON(cpu_is_offline(cpu)); | 473 | WARN_ON(cpu_is_offline(cpu)); |
489 | send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); | 474 | send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); |
@@ -515,36 +500,78 @@ void unlock_ipi_call_lock(void) | |||
515 | 500 | ||
516 | static struct call_data_struct *call_data; | 501 | static struct call_data_struct *call_data; |
517 | 502 | ||
503 | static void __smp_call_function(void (*func) (void *info), void *info, | ||
504 | int nonatomic, int wait) | ||
505 | { | ||
506 | struct call_data_struct data; | ||
507 | int cpus = num_online_cpus() - 1; | ||
508 | |||
509 | if (!cpus) | ||
510 | return; | ||
511 | |||
512 | data.func = func; | ||
513 | data.info = info; | ||
514 | atomic_set(&data.started, 0); | ||
515 | data.wait = wait; | ||
516 | if (wait) | ||
517 | atomic_set(&data.finished, 0); | ||
518 | |||
519 | call_data = &data; | ||
520 | mb(); | ||
521 | |||
522 | /* Send a message to all other CPUs and wait for them to respond */ | ||
523 | send_IPI_allbutself(CALL_FUNCTION_VECTOR); | ||
524 | |||
525 | /* Wait for response */ | ||
526 | while (atomic_read(&data.started) != cpus) | ||
527 | cpu_relax(); | ||
528 | |||
529 | if (wait) | ||
530 | while (atomic_read(&data.finished) != cpus) | ||
531 | cpu_relax(); | ||
532 | } | ||
533 | |||
534 | |||
518 | /** | 535 | /** |
519 | * smp_call_function(): Run a function on all other CPUs. | 536 | * smp_call_function_mask(): Run a function on a set of other CPUs. |
537 | * @mask: The set of cpus to run on. Must not include the current cpu. | ||
520 | * @func: The function to run. This must be fast and non-blocking. | 538 | * @func: The function to run. This must be fast and non-blocking. |
521 | * @info: An arbitrary pointer to pass to the function. | 539 | * @info: An arbitrary pointer to pass to the function. |
522 | * @nonatomic: currently unused. | ||
523 | * @wait: If true, wait (atomically) until function has completed on other CPUs. | 540 | * @wait: If true, wait (atomically) until function has completed on other CPUs. |
524 | * | 541 | * |
525 | * Returns 0 on success, else a negative status code. Does not return until | 542 | * Returns 0 on success, else a negative status code. |
526 | * remote CPUs are nearly ready to execute <<func>> or are or have executed. | 543 | * |
544 | * If @wait is true, then returns once @func has returned; otherwise | ||
545 | * it returns just before the target cpu calls @func. | ||
527 | * | 546 | * |
528 | * You must not call this function with disabled interrupts or from a | 547 | * You must not call this function with disabled interrupts or from a |
529 | * hardware interrupt handler or from a bottom half handler. | 548 | * hardware interrupt handler or from a bottom half handler. |
530 | */ | 549 | */ |
531 | int smp_call_function (void (*func) (void *info), void *info, int nonatomic, | 550 | int native_smp_call_function_mask(cpumask_t mask, |
532 | int wait) | 551 | void (*func)(void *), void *info, |
552 | int wait) | ||
533 | { | 553 | { |
534 | struct call_data_struct data; | 554 | struct call_data_struct data; |
555 | cpumask_t allbutself; | ||
535 | int cpus; | 556 | int cpus; |
536 | 557 | ||
558 | /* Can deadlock when called with interrupts disabled */ | ||
559 | WARN_ON(irqs_disabled()); | ||
560 | |||
537 | /* Holding any lock stops cpus from going down. */ | 561 | /* Holding any lock stops cpus from going down. */ |
538 | spin_lock(&call_lock); | 562 | spin_lock(&call_lock); |
539 | cpus = num_online_cpus() - 1; | 563 | |
564 | allbutself = cpu_online_map; | ||
565 | cpu_clear(smp_processor_id(), allbutself); | ||
566 | |||
567 | cpus_and(mask, mask, allbutself); | ||
568 | cpus = cpus_weight(mask); | ||
569 | |||
540 | if (!cpus) { | 570 | if (!cpus) { |
541 | spin_unlock(&call_lock); | 571 | spin_unlock(&call_lock); |
542 | return 0; | 572 | return 0; |
543 | } | 573 | } |
544 | 574 | ||
545 | /* Can deadlock when called with interrupts disabled */ | ||
546 | WARN_ON(irqs_disabled()); | ||
547 | |||
548 | data.func = func; | 575 | data.func = func; |
549 | data.info = info; | 576 | data.info = info; |
550 | atomic_set(&data.started, 0); | 577 | atomic_set(&data.started, 0); |
@@ -554,9 +581,12 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, | |||
554 | 581 | ||
555 | call_data = &data; | 582 | call_data = &data; |
556 | mb(); | 583 | mb(); |
557 | 584 | ||
558 | /* Send a message to all other CPUs and wait for them to respond */ | 585 | /* Send a message to other CPUs */ |
559 | send_IPI_allbutself(CALL_FUNCTION_VECTOR); | 586 | if (cpus_equal(mask, allbutself)) |
587 | send_IPI_allbutself(CALL_FUNCTION_VECTOR); | ||
588 | else | ||
589 | send_IPI_mask(mask, CALL_FUNCTION_VECTOR); | ||
560 | 590 | ||
561 | /* Wait for response */ | 591 | /* Wait for response */ |
562 | while (atomic_read(&data.started) != cpus) | 592 | while (atomic_read(&data.started) != cpus) |
@@ -569,15 +599,68 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, | |||
569 | 599 | ||
570 | return 0; | 600 | return 0; |
571 | } | 601 | } |
602 | |||
603 | /** | ||
604 | * smp_call_function(): Run a function on all other CPUs. | ||
605 | * @func: The function to run. This must be fast and non-blocking. | ||
606 | * @info: An arbitrary pointer to pass to the function. | ||
607 | * @nonatomic: Unused. | ||
608 | * @wait: If true, wait (atomically) until function has completed on other CPUs. | ||
609 | * | ||
610 | * Returns 0 on success, else a negative status code. | ||
611 | * | ||
612 | * If @wait is true, then returns once @func has returned; otherwise | ||
613 | * it returns just before the target cpu calls @func. | ||
614 | * | ||
615 | * You must not call this function with disabled interrupts or from a | ||
616 | * hardware interrupt handler or from a bottom half handler. | ||
617 | */ | ||
618 | int smp_call_function(void (*func) (void *info), void *info, int nonatomic, | ||
619 | int wait) | ||
620 | { | ||
621 | return smp_call_function_mask(cpu_online_map, func, info, wait); | ||
622 | } | ||
572 | EXPORT_SYMBOL(smp_call_function); | 623 | EXPORT_SYMBOL(smp_call_function); |
573 | 624 | ||
625 | /** | ||
626 | * smp_call_function_single - Run a function on another CPU | ||
627 | * @cpu: The target CPU. Cannot be the calling CPU. | ||
628 | * @func: The function to run. This must be fast and non-blocking. | ||
629 | * @info: An arbitrary pointer to pass to the function. | ||
630 | * @nonatomic: Unused. | ||
631 | * @wait: If true, wait until function has completed on other CPUs. | ||
632 | * | ||
633 | * Returns 0 on success, else a negative status code. | ||
634 | * | ||
635 | * If @wait is true, then returns once @func has returned; otherwise | ||
636 | * it returns just before the target cpu calls @func. | ||
637 | */ | ||
638 | int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
639 | int nonatomic, int wait) | ||
640 | { | ||
641 | /* prevent preemption and reschedule on another processor */ | ||
642 | int ret; | ||
643 | int me = get_cpu(); | ||
644 | if (cpu == me) { | ||
645 | WARN_ON(1); | ||
646 | put_cpu(); | ||
647 | return -EBUSY; | ||
648 | } | ||
649 | |||
650 | ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait); | ||
651 | |||
652 | put_cpu(); | ||
653 | return ret; | ||
654 | } | ||
655 | EXPORT_SYMBOL(smp_call_function_single); | ||
656 | |||
574 | static void stop_this_cpu (void * dummy) | 657 | static void stop_this_cpu (void * dummy) |
575 | { | 658 | { |
659 | local_irq_disable(); | ||
576 | /* | 660 | /* |
577 | * Remove this CPU: | 661 | * Remove this CPU: |
578 | */ | 662 | */ |
579 | cpu_clear(smp_processor_id(), cpu_online_map); | 663 | cpu_clear(smp_processor_id(), cpu_online_map); |
580 | local_irq_disable(); | ||
581 | disable_local_APIC(); | 664 | disable_local_APIC(); |
582 | if (cpu_data[smp_processor_id()].hlt_works_ok) | 665 | if (cpu_data[smp_processor_id()].hlt_works_ok) |
583 | for(;;) halt(); | 666 | for(;;) halt(); |
@@ -588,13 +671,18 @@ static void stop_this_cpu (void * dummy) | |||
588 | * this function calls the 'stop' function on all other CPUs in the system. | 671 | * this function calls the 'stop' function on all other CPUs in the system. |
589 | */ | 672 | */ |
590 | 673 | ||
591 | void smp_send_stop(void) | 674 | void native_smp_send_stop(void) |
592 | { | 675 | { |
593 | smp_call_function(stop_this_cpu, NULL, 1, 0); | 676 | /* Don't deadlock on the call lock in panic */ |
677 | int nolock = !spin_trylock(&call_lock); | ||
678 | unsigned long flags; | ||
594 | 679 | ||
595 | local_irq_disable(); | 680 | local_irq_save(flags); |
681 | __smp_call_function(stop_this_cpu, NULL, 0, 0); | ||
682 | if (!nolock) | ||
683 | spin_unlock(&call_lock); | ||
596 | disable_local_APIC(); | 684 | disable_local_APIC(); |
597 | local_irq_enable(); | 685 | local_irq_restore(flags); |
598 | } | 686 | } |
599 | 687 | ||
600 | /* | 688 | /* |
@@ -633,77 +721,6 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs) | |||
633 | } | 721 | } |
634 | } | 722 | } |
635 | 723 | ||
636 | /* | ||
637 | * this function sends a 'generic call function' IPI to one other CPU | ||
638 | * in the system. | ||
639 | * | ||
640 | * cpu is a standard Linux logical CPU number. | ||
641 | */ | ||
642 | static void | ||
643 | __smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
644 | int nonatomic, int wait) | ||
645 | { | ||
646 | struct call_data_struct data; | ||
647 | int cpus = 1; | ||
648 | |||
649 | data.func = func; | ||
650 | data.info = info; | ||
651 | atomic_set(&data.started, 0); | ||
652 | data.wait = wait; | ||
653 | if (wait) | ||
654 | atomic_set(&data.finished, 0); | ||
655 | |||
656 | call_data = &data; | ||
657 | wmb(); | ||
658 | /* Send a message to all other CPUs and wait for them to respond */ | ||
659 | send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR); | ||
660 | |||
661 | /* Wait for response */ | ||
662 | while (atomic_read(&data.started) != cpus) | ||
663 | cpu_relax(); | ||
664 | |||
665 | if (!wait) | ||
666 | return; | ||
667 | |||
668 | while (atomic_read(&data.finished) != cpus) | ||
669 | cpu_relax(); | ||
670 | } | ||
671 | |||
672 | /* | ||
673 | * smp_call_function_single - Run a function on another CPU | ||
674 | * @func: The function to run. This must be fast and non-blocking. | ||
675 | * @info: An arbitrary pointer to pass to the function. | ||
676 | * @nonatomic: Currently unused. | ||
677 | * @wait: If true, wait until function has completed on other CPUs. | ||
678 | * | ||
679 | * Retrurns 0 on success, else a negative status code. | ||
680 | * | ||
681 | * Does not return until the remote CPU is nearly ready to execute <func> | ||
682 | * or is or has executed. | ||
683 | */ | ||
684 | |||
685 | int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
686 | int nonatomic, int wait) | ||
687 | { | ||
688 | /* prevent preemption and reschedule on another processor */ | ||
689 | int me = get_cpu(); | ||
690 | if (cpu == me) { | ||
691 | WARN_ON(1); | ||
692 | put_cpu(); | ||
693 | return -EBUSY; | ||
694 | } | ||
695 | |||
696 | /* Can deadlock when called with interrupts disabled */ | ||
697 | WARN_ON(irqs_disabled()); | ||
698 | |||
699 | spin_lock_bh(&call_lock); | ||
700 | __smp_call_function_single(cpu, func, info, nonatomic, wait); | ||
701 | spin_unlock_bh(&call_lock); | ||
702 | put_cpu(); | ||
703 | return 0; | ||
704 | } | ||
705 | EXPORT_SYMBOL(smp_call_function_single); | ||
706 | |||
707 | static int convert_apicid_to_cpu(int apic_id) | 724 | static int convert_apicid_to_cpu(int apic_id) |
708 | { | 725 | { |
709 | int i; | 726 | int i; |
@@ -730,3 +747,14 @@ int safe_smp_processor_id(void) | |||
730 | 747 | ||
731 | return cpuid >= 0 ? cpuid : 0; | 748 | return cpuid >= 0 ? cpuid : 0; |
732 | } | 749 | } |
750 | |||
751 | struct smp_ops smp_ops = { | ||
752 | .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, | ||
753 | .smp_prepare_cpus = native_smp_prepare_cpus, | ||
754 | .cpu_up = native_cpu_up, | ||
755 | .smp_cpus_done = native_smp_cpus_done, | ||
756 | |||
757 | .smp_send_stop = native_smp_send_stop, | ||
758 | .smp_send_reschedule = native_smp_send_reschedule, | ||
759 | .smp_call_function_mask = native_smp_call_function_mask, | ||
760 | }; | ||