1 /* $Id: mpnotification-r0drv-linux.c $ */
3 * IPRT - Multiprocessor Event Notifications, Ring-0 Driver, Linux.
7 * Copyright (C) 2008-2016 Oracle Corporation
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
28 /*********************************************************************************************************************************
30 *********************************************************************************************************************************/
31 #include "the-linux-kernel.h"
32 #include "internal/iprt.h"
34 #include <iprt/asm-amd64-x86.h>
36 #include <iprt/cpuset.h>
37 #include <iprt/thread.h>
38 #include "r0drv/mp-r0drv.h"
41 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 71) && defined(CONFIG_SMP)
44 /*********************************************************************************************************************************
45 * Internal Functions *
46 *********************************************************************************************************************************/
47 static int rtMpNotificationLinuxCallback(struct notifier_block
*pNotifierBlock
, unsigned long ulNativeEvent
, void *pvCpu
);
50 /*********************************************************************************************************************************
52 *********************************************************************************************************************************/
54 * The notifier block we use for registering the callback.
56 static struct notifier_block g_NotifierBlock
=
58 .notifier_call
= rtMpNotificationLinuxCallback
,
63 # ifdef CPU_DOWN_FAILED
65 * The set of CPUs we've seen going offline recently.
67 static RTCPUSET g_MpPendingOfflineSet
;
72 * The native callback.
74 * @returns NOTIFY_DONE.
75 * @param pNotifierBlock Pointer to g_NotifierBlock.
76 * @param ulNativeEvent The native event.
77 * @param pvCpu The cpu id cast into a pointer value.
79 * @remarks This can fire with preemption enabled and on any CPU.
81 static int rtMpNotificationLinuxCallback(struct notifier_block
*pNotifierBlock
, unsigned long ulNativeEvent
, void *pvCpu
)
83 bool fProcessEvent
= false;
84 RTCPUID idCpu
= (uintptr_t)pvCpu
;
85 NOREF(pNotifierBlock
);
88 * Note that redhat/CentOS ported _some_ of the FROZEN macros
89 * back to their 2.6.18-92.1.10.el5 kernel but actually don't
90 * use them. Thus we have to test for both CPU_TASKS_FROZEN and
91 * the individual event variants.
93 switch (ulNativeEvent
)
96 * Pick up online events or failures to go offline.
97 * Ignore failure events for CPUs we didn't see go offline.
99 # ifdef CPU_DOWN_FAILED
100 case CPU_DOWN_FAILED
:
101 # if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
102 case CPU_DOWN_FAILED_FROZEN
:
104 if (!RTCpuSetIsMember(&g_MpPendingOfflineSet
, idCpu
))
105 break; /* fProcessEvents = false */
109 # if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
110 case CPU_ONLINE_FROZEN
:
112 # ifdef CPU_DOWN_FAILED
113 RTCpuSetDel(&g_MpPendingOfflineSet
, idCpu
);
115 fProcessEvent
= true;
119 * Pick the earliest possible offline event.
120 * The only important thing here is that we get the event and that
123 # ifdef CPU_DOWN_PREPARE
124 case CPU_DOWN_PREPARE
:
125 # if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
126 case CPU_DOWN_PREPARE_FROZEN
:
128 fProcessEvent
= true;
131 # if defined(CPU_TASKS_FROZEN) && defined(CPU_DEAD_FROZEN)
132 case CPU_DEAD_FROZEN
:
134 /* Don't process CPU_DEAD notifications. */
136 # ifdef CPU_DOWN_FAILED
137 RTCpuSetAdd(&g_MpPendingOfflineSet
, idCpu
);
145 switch (ulNativeEvent
)
147 # ifdef CPU_DOWN_FAILED
148 case CPU_DOWN_FAILED
:
149 # if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
150 case CPU_DOWN_FAILED_FROZEN
:
154 # if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
155 case CPU_ONLINE_FROZEN
:
157 rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE
, idCpu
);
160 # ifdef CPU_DOWN_PREPARE
161 case CPU_DOWN_PREPARE
:
162 # if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
163 case CPU_DOWN_PREPARE_FROZEN
:
165 rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE
, idCpu
);
174 DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
177 IPRT_LINUX_SAVE_EFL_AC();
179 # ifdef CPU_DOWN_FAILED
180 RTCpuSetEmpty(&g_MpPendingOfflineSet
);
183 rc
= register_cpu_notifier(&g_NotifierBlock
);
184 IPRT_LINUX_RESTORE_EFL_AC();
185 AssertMsgReturn(!rc
, ("%d\n", rc
), RTErrConvertFromErrno(rc
));
190 DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
192 IPRT_LINUX_SAVE_EFL_AC();
193 unregister_cpu_notifier(&g_NotifierBlock
);
194 IPRT_LINUX_RESTORE_EFL_AC();
197 #else /* Not supported / Not needed */
199 DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
204 DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
208 #endif /* Not supported / Not needed */