/branches/sparc/kernel/arch/sparc64/src/smp/sun4v/smp.c |
---|
34,6 → 34,7 |
*/ |
#include <smp/smp.h> |
#include <smp/ipi.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <cpu.h> |
#include <arch/cpu.h> |
47,6 → 48,7 |
#include <print.h> |
#include <arch/sun4v/hypercall.h> |
#include <arch/sun4v/md.h> |
#include <arch/sun4v/ipi.h> |
#include <time/delay.h> |
#define CPU_STATE_RUNNING 2 |
72,6 → 74,7 |
/** Wake application processors up. */ |
void kmp(void *arg) |
{ |
#if 1 |
(void) arg; |
uint64_t myid; |
111,7 → 114,67 |
") timed out\n", __func__, i); |
} |
#else |
asm volatile ( |
"setx temp_cpu_mondo_handler, %g4, %g6 \n" |
//"setx 0x80246ad8, %g4, %g7 \n" |
"setx 0x80200f80, %g4, %g7 \n" |
"ldx [%g6], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x8], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x10], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x18], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x20], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x28], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x30], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x38], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"add %g7, 0x8, %g7 \n" |
"ldx [%g6 + 0x40], %g4 \n" |
"stxa %g4, [%g7] 0x14 \n" |
"membar #Sync \n" |
"flush %i7" |
); |
delay(1000); |
printf("Result: %d\n", ipi_unicast_to((void (*)(void)) 1234, 1)); |
if (waitq_sleep_timeout(&ap_completion_wq, 10000000, SYNCH_FLAGS_NONE) == |
ESYNCH_TIMEOUT) |
printf("%s: waiting for processor (cpuid = %" PRIu32 |
") timed out\n", __func__, 1); |
#endif |
} |
/** @} |
/branches/sparc/kernel/arch/sparc64/src/smp/sun4v/ipi.c |
---|
0,0 → 1,123 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#include <smp/ipi.h> |
#include <cpu.h> |
#include <config.h> |
#include <interrupt.h> |
#include <arch/asm.h> |
#include <arch/cpu.h> |
#include <arch/sun4v/hypercall.h> |
#include <arch/sun4v/ipi.h> |
#define IPI_MESSAGE_SIZE 8 |
static uint64_t data[MAX_NUM_STRANDS][IPI_MESSAGE_SIZE] |
__attribute__ ((aligned (64))); |
static uint16_t ipi_cpu_list[MAX_NUM_STRANDS][MAX_NUM_STRANDS]; |
/** |
* Sends an inter-processor interrupt to all virtual processors whose IDs are |
* listed in the list. |
* |
* @param func address of the function to be invoked on the recipient |
* @param cpu_list list of CPU IDs (16-bit identifiers) of the recipients |
* @param list_size number of recipients (number of valid cpu_list entries) |
* |
* @return error code returned by the CPU_MONDO_SEND hypercall |
*/ |
uint64_t ipi_brodcast_to(void (*func)(void), uint16_t cpu_list[MAX_NUM_STRANDS], |
uint64_t list_size) { |
data[CPU->arch.id][0] = (uint64_t) func; |
unsigned int i; |
for (i = 0; i < list_size; i++) { |
ipi_cpu_list[CPU->arch.id][i] = cpu_list[i]; |
} |
return __hypercall_fast3(CPU_MONDO_SEND, list_size, |
KA2PA(ipi_cpu_list[CPU->arch.id]), KA2PA(data[CPU->arch.id])); |
} |
/** |
* Send an inter-processor interrupt to a particular CPU. |
* |
* @param func address of the function to be invoked on the recipient |
* @param cpu_is CPU ID (16-bit identifier) of the recipient |
* |
* @return error code returned by the CPU_MONDO_SEND hypercall |
*/ |
uint64_t ipi_unicast_to(void (*func)(void), uint16_t cpu_id) { |
ipi_cpu_list[CPU->arch.id][0] = cpu_id; |
return ipi_brodcast_to(func, ipi_cpu_list[CPU->arch.id], 1); |
} |
/* |
* Deliver IPI to all processors except the current one. |
* |
* We assume that interrupts are disabled. |
* |
* @param ipi IPI number. |
*/ |
void ipi_broadcast_arch(int ipi) |
{ |
void (* func)(void); |
switch (ipi) { |
case IPI_TLB_SHOOTDOWN: |
func = tlb_shootdown_ipi_recv; |
break; |
default: |
panic("Unknown IPI (%d).\n", ipi); |
break; |
} |
unsigned int i; |
unsigned idx = 0; |
for (i = 0; i < config.cpu_active; i++) { |
if (&cpus[i] == CPU) { |
continue; |
} |
ipi_cpu_list[CPU->id][idx] = (uint16_t) cpus[i].id; |
idx++; |
} |
ipi_brodcast_to(func, ipi_cpu_list[CPU->arch.id], idx); |
} |
/** @} |
*/ |
/branches/sparc/kernel/arch/sparc64/src/smp/ipi.c |
---|
File deleted |
/branches/sparc/kernel/arch/sparc64/src/smp/sun4u/ipi.c |
---|
0,0 → 1,174 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#include <smp/ipi.h> |
#include <cpu.h> |
#include <arch.h> |
#include <arch/cpu.h> |
#include <arch/asm.h> |
#include <config.h> |
#include <mm/tlb.h> |
#include <arch/interrupt.h> |
#include <arch/trap/interrupt.h> |
#include <arch/barrier.h> |
#include <preemption.h> |
#include <time/delay.h> |
#include <panic.h> |
/** Set the contents of the outgoing interrupt vector data. |
* |
* The first data item (data 0) will be set to the value of func, the |
* rest of the vector will contain zeros. |
* |
* This is a helper function used from within the cross_call function. |
* |
* @param func value the first data item of the vector will be set to |
*/ |
static inline void set_intr_w_data(void (* func)(void)) |
{ |
#if defined (US) |
asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_0, (uintptr_t) func); |
asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_1, 0); |
asi_u64_write(ASI_INTR_W, ASI_UDB_INTR_W_DATA_2, 0); |
#elif defined (US3) |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_0, (uintptr_t) func); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_1, 0); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_2, 0); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_3, 0); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_4, 0); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_5, 0); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_6, 0); |
asi_u64_write(ASI_INTR_W, VA_INTR_W_DATA_7, 0); |
#endif |
} |
/** Invoke function on another processor. |
* |
* Currently, only functions without arguments are supported. |
* Supporting more arguments in the future should be no big deal. |
* |
* Interrupts must be disabled prior to this call. |
* |
* @param mid MID of the target processor. |
* @param func Function to be invoked. |
*/ |
static void cross_call(int mid, void (* func)(void)) |
{ |
uint64_t status; |
bool done; |
/* |
* This function might enable interrupts for a while. |
* In order to prevent migration to another processor, |
* we explicitly disable preemption. |
*/ |
preemption_disable(); |
status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0); |
if (status & INTR_DISPATCH_STATUS_BUSY) |
panic("Interrupt Dispatch Status busy bit set\n"); |
ASSERT(!(pstate_read() & PSTATE_IE_BIT)); |
do { |
set_intr_w_data(func); |
asi_u64_write(ASI_INTR_W, |
(mid << INTR_VEC_DISPATCH_MID_SHIFT) | |
VA_INTR_W_DISPATCH, 0); |
membar(); |
do { |
status = asi_u64_read(ASI_INTR_DISPATCH_STATUS, 0); |
} while (status & INTR_DISPATCH_STATUS_BUSY); |
done = !(status & INTR_DISPATCH_STATUS_NACK); |
if (!done) { |
/* |
* Prevent deadlock. |
*/ |
(void) interrupts_enable(); |
delay(20 + (tick_read() & 0xff)); |
(void) interrupts_disable(); |
} |
} while (done); |
preemption_enable(); |
} |
/* |
* Deliver IPI to all processors except the current one. |
* |
* The sparc64 architecture does not support any group addressing |
* which is found, for instance, on ia32 and amd64. Therefore we |
* need to simulate the broadcast by sending the message to |
* all target processors step by step. |
* |
* We assume that interrupts are disabled. |
* |
* @param ipi IPI number. |
*/ |
void ipi_broadcast_arch(int ipi) |
{ |
unsigned int i; |
void (* func)(void); |
switch (ipi) { |
case IPI_TLB_SHOOTDOWN: |
func = tlb_shootdown_ipi_recv; |
break; |
default: |
panic("Unknown IPI (%d).\n", ipi); |
break; |
} |
/* |
* As long as we don't support hot-plugging |
* or hot-unplugging of CPUs, we can walk |
* the cpus array and read processor's MID |
* without locking. |
*/ |
for (i = 0; i < config.cpu_active; i++) { |
if (&cpus[i] == CPU) |
continue; /* skip the current CPU */ |
cross_call(cpus[i].arch.mid, func); |
} |
} |
/** @} |
*/ |