VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c

Last change on this file was 100191, checked in by vboxsync, 12 months ago

*: Some of the easy build fixes for linux.arm64 not warranting their own commit, bugref:10457

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.5 KB
Line 
1/* $Id: mpnotification-r0drv-linux.c 100191 2023-06-16 08:04:11Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor Event Notifications, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "the-linux-kernel.h"
42#include "internal/iprt.h"
43
44#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
45# include <iprt/asm-amd64-x86.h>
46#endif
47#include <iprt/errcore.h>
48#include <iprt/cpuset.h>
49#include <iprt/thread.h>
50#include "r0drv/mp-r0drv.h"
51
52#if RTLNX_VER_MIN(4,10,0)
53
54static enum cpuhp_state g_rtR0MpOnline;
55
56/*
57 * Linux 4.10 completely removed CPU notifiers. So let's switch to CPU hotplug
58 * notification.
59 */
60
61static int rtR0MpNotificationLinuxOnline(unsigned int cpu)
62{
63 RTCPUID idCpu = RTMpCpuIdFromSetIndex(cpu);
64 rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
65 return 0;
66}
67
68static int rtR0MpNotificationLinuxOffline(unsigned int cpu)
69{
70 RTCPUID idCpu = RTMpCpuIdFromSetIndex(cpu);
71 rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
72 return 0;
73}
74
75DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
76{
77 int rc;
78 IPRT_LINUX_SAVE_EFL_AC();
79 rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "vboxdrv:online",
80 rtR0MpNotificationLinuxOnline, rtR0MpNotificationLinuxOffline);
81 IPRT_LINUX_RESTORE_EFL_AC();
82 /*
83 * cpuhp_setup_state_nocalls() returns a positive state number for
84 * CPUHP_AP_ONLINE_DYN or -ENOSPC if there is no free slot available
85 * (see cpuhp_reserve_state / definition of CPUHP_AP_ONLINE_DYN).
86 */
87 AssertMsgReturn(rc > 0, ("%d\n", rc), RTErrConvertFromErrno(rc));
88 g_rtR0MpOnline = rc;
89 return VINF_SUCCESS;
90}
91
92
93DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
94{
95 IPRT_LINUX_SAVE_EFL_AC();
96 cpuhp_remove_state_nocalls(g_rtR0MpOnline);
97 IPRT_LINUX_RESTORE_EFL_AC();
98}
99
100#elif RTLNX_VER_MIN(2,5,71) && defined(CONFIG_SMP)
101
102static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu);
103
104/**
105 * The notifier block we use for registering the callback.
106 */
107static struct notifier_block g_NotifierBlock =
108{
109 .notifier_call = rtMpNotificationLinuxCallback,
110 .next = NULL,
111 .priority = 0
112};
113
114# ifdef CPU_DOWN_FAILED
115/**
116 * The set of CPUs we've seen going offline recently.
117 */
118static RTCPUSET g_MpPendingOfflineSet;
119# endif
120
121
122/**
123 * The native callback.
124 *
125 * @returns NOTIFY_DONE.
126 * @param pNotifierBlock Pointer to g_NotifierBlock.
127 * @param ulNativeEvent The native event.
128 * @param pvCpu The cpu id cast into a pointer value.
129 *
130 * @remarks This can fire with preemption enabled and on any CPU.
131 */
132static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu)
133{
134 bool fProcessEvent = false;
135 RTCPUID idCpu = (uintptr_t)pvCpu;
136 NOREF(pNotifierBlock);
137
138 /*
139 * Note that redhat/CentOS ported _some_ of the FROZEN macros
140 * back to their 2.6.18-92.1.10.el5 kernel but actually don't
141 * use them. Thus we have to test for both CPU_TASKS_FROZEN and
142 * the individual event variants.
143 */
144 switch (ulNativeEvent)
145 {
146 /*
147 * Pick up online events or failures to go offline.
148 * Ignore failure events for CPUs we didn't see go offline.
149 */
150# ifdef CPU_DOWN_FAILED
151 case CPU_DOWN_FAILED:
152# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
153 case CPU_DOWN_FAILED_FROZEN:
154# endif
155 if (!RTCpuSetIsMember(&g_MpPendingOfflineSet, idCpu))
156 break; /* fProcessEvents = false */
157 /* fall thru */
158# endif
159 case CPU_ONLINE:
160# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
161 case CPU_ONLINE_FROZEN:
162# endif
163# ifdef CPU_DOWN_FAILED
164 RTCpuSetDel(&g_MpPendingOfflineSet, idCpu);
165# endif
166 fProcessEvent = true;
167 break;
168
169 /*
170 * Pick the earliest possible offline event.
171 * The only important thing here is that we get the event and that
172 * it's exactly one.
173 */
174# ifdef CPU_DOWN_PREPARE
175 case CPU_DOWN_PREPARE:
176# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
177 case CPU_DOWN_PREPARE_FROZEN:
178# endif
179 fProcessEvent = true;
180# else
181 case CPU_DEAD:
182# if defined(CPU_TASKS_FROZEN) && defined(CPU_DEAD_FROZEN)
183 case CPU_DEAD_FROZEN:
184# endif
185 /* Don't process CPU_DEAD notifications. */
186# endif
187# ifdef CPU_DOWN_FAILED
188 RTCpuSetAdd(&g_MpPendingOfflineSet, idCpu);
189# endif
190 break;
191 }
192
193 if (!fProcessEvent)
194 return NOTIFY_DONE;
195
196 switch (ulNativeEvent)
197 {
198# ifdef CPU_DOWN_FAILED
199 case CPU_DOWN_FAILED:
200# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
201 case CPU_DOWN_FAILED_FROZEN:
202# endif
203# endif
204 case CPU_ONLINE:
205# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
206 case CPU_ONLINE_FROZEN:
207# endif
208 rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
209 break;
210
211# ifdef CPU_DOWN_PREPARE
212 case CPU_DOWN_PREPARE:
213# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
214 case CPU_DOWN_PREPARE_FROZEN:
215# endif
216 rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
217 break;
218# endif
219 }
220
221 return NOTIFY_DONE;
222}
223
224
225DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
226{
227 int rc;
228 IPRT_LINUX_SAVE_EFL_AC();
229
230# ifdef CPU_DOWN_FAILED
231 RTCpuSetEmpty(&g_MpPendingOfflineSet);
232# endif
233
234 rc = register_cpu_notifier(&g_NotifierBlock);
235 IPRT_LINUX_RESTORE_EFL_AC();
236 AssertMsgReturn(!rc, ("%d\n", rc), RTErrConvertFromErrno(rc));
237 return VINF_SUCCESS;
238}
239
240
241DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
242{
243 IPRT_LINUX_SAVE_EFL_AC();
244 unregister_cpu_notifier(&g_NotifierBlock);
245 IPRT_LINUX_RESTORE_EFL_AC();
246}
247
248#else /* Not supported / Not needed */
249
250DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
251{
252 return VINF_SUCCESS;
253}
254
255DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
256{
257}
258
259#endif /* Not supported / Not needed */
260
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use