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:
parent
6cd505cee7
commit
ef7bac18bb
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user