Implemented call_all_cpus(), and get_cpuid() properly (tested only the latter, though).

The "data_ptr" parameter is now only freed if you specify SMP_MSG_FLAG_FREE_ARG
when sending the ICI message.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14519 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-10-25 18:18:11 +00:00
parent 6cd505cee7
commit ef7bac18bb
3 changed files with 67 additions and 25 deletions

View File

@ -21,14 +21,18 @@ enum {
SMP_MSG_GLOBAL_INVL_PAGE,
SMP_MSG_RESCHEDULE,
SMP_MSG_CPU_HALT,
SMP_MSG_1,
SMP_MSG_CALL_FUNCTION,
};
enum {
SMP_MSG_FLAG_ASYNC = 0,
SMP_MSG_FLAG_SYNC,
SMP_MSG_FLAG_ASYNC = 0x0,
SMP_MSG_FLAG_SYNC = 0x1,
SMP_MSG_FLAG_FREE_ARG = 0x2,
};
typedef void (*smp_call_func)(uint32 data1, int32 currentCPU, uint32 data2, uint32 data3);
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
@ -15,25 +15,44 @@
#include <string.h>
extern void cpuid(uint32 selector, cpuid_info *info);
extern uint32 cv_factor;
uint32 sCpuType;
int32 sCpuRevision;
int64 sCpuClockSpeed;
status_t
get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 cpuNum)
static bool
get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint32 eaxRegister, uint32 forCPU)
{
if (cpuNum >= (uint32)smp_get_num_cpus())
if (currentCPU != forCPU)
return false;
get_current_cpuid(info, eaxRegister);
return true;
}
status_t
get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 forCPU)
{
uint32 numCPUs = (uint32)smp_get_num_cpus();
cpu_status state;
if (forCPU >= numCPUs)
return B_BAD_VALUE;
// ToDo: cpu_num is ignored, we should use the call_all_cpus() function
// to fix this.
// prevent us from being rescheduled
state = disable_interrupts();
return get_current_cpuid(info, eaxRegister);
// ToDo: as long as we only run on pentium-class systems, we can assume
// that the CPU supports cpuid.
if (!get_cpuid_for(info, smp_get_current_cpu(), eaxRegister, forCPU)) {
smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (uint32)info,
eaxRegister, forCPU, (void *)get_cpuid_for, SMP_MSG_FLAG_SYNC);
}
restore_interrupts(state);
return B_OK;
}

View File

@ -184,9 +184,10 @@ release_spinlock(spinlock *lock)
}
// finds a free message and gets it
// NOTE: has side effect of disabling interrupts
// return value is interrupt state
/** Finds a free message and gets it.
* NOTE: has side effect of disabling interrupts
* return value is the former interrupt state
*/
static cpu_status
find_free_message(struct smp_msg **msg)
@ -328,10 +329,10 @@ finish_message_processing(int currentCPU, struct smp_msg *msg, int source_mailbo
release_spinlock(spinlock);
if (msg->data_ptr != NULL)
if ((msg->flags & SMP_MSG_FLAG_FREE_ARG) != 0 && msg->data_ptr != NULL)
free(msg->data_ptr);
if (msg->flags == SMP_MSG_FLAG_SYNC) {
if (msg->flags & SMP_MSG_FLAG_SYNC) {
msg->done = true;
// the caller cpu should now free the message
} else {
@ -373,7 +374,13 @@ process_pending_ici(int32 currentCPU)
halt = true;
dprintf("cpu %ld halted!\n", currentCPU);
break;
case SMP_MSG_1:
case SMP_MSG_CALL_FUNCTION:
{
smp_call_func func = (smp_call_func)msg->data_ptr;
func(msg->data, currentCPU, msg->data2, msg->data3);
break;
}
default:
dprintf("smp_intercpu_int_handler: got unknown message %ld\n", msg->message);
}
@ -392,6 +399,9 @@ process_pending_ici(int32 currentCPU)
}
// #pragma mark -
int
smp_intercpu_int_handler(void)
{
@ -449,7 +459,7 @@ smp_send_ici(int32 targetCPU, int32 message, uint32 data, uint32 data2, uint32 d
arch_smp_send_ici(targetCPU);
if (flags == SMP_MSG_FLAG_SYNC) {
if (flags & SMP_MSG_FLAG_SYNC) {
// wait for the other cpu to finish processing it
// the interrupt handler will ref count it to <0
// if the message is sync after it has removed it from the mailbox
@ -508,7 +518,7 @@ smp_send_broadcast_ici(int32 message, uint32 data, uint32 data2, uint32 data3,
TRACE(("smp_send_broadcast_ici: sent interrupt\n"));
if (flags == SMP_MSG_FLAG_SYNC) {
if (flags & SMP_MSG_FLAG_SYNC) {
// wait for the other cpus to finish processing it
// the interrupt handler will ref count it to <0
// if the message is sync after it has removed it from the mailbox
@ -652,9 +662,18 @@ smp_get_current_cpu(void)
void
call_all_cpus(void (*f)(void *, int), void *cookie)
call_all_cpus(void (*func)(void *, int), void *cookie)
{
// ToDo: this is a dummy, but at least it works for single CPU machines
f(cookie, smp_get_current_cpu());
cpu_status state = disable_interrupts();
if (smp_get_num_cpus() > 1) {
smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (uint32)cookie,
0, 0, (void *)func, SMP_MSG_FLAG_SYNC);
}
// we need to call this function ourselves as well
func(cookie, smp_get_current_cpu());
restore_interrupts(state);
}