VirtualBox

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

Last change on this file since 97698 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • 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 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor Event Notifications, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2008-2022 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#include <iprt/asm-amd64-x86.h>
45#include <iprt/errcore.h>
46#include <iprt/cpuset.h>
47#include <iprt/thread.h>
48#include "r0drv/mp-r0drv.h"
49
50#if RTLNX_VER_MIN(4,10,0)
51
52static enum cpuhp_state g_rtR0MpOnline;
53
54/*
55 * Linux 4.10 completely removed CPU notifiers. So let's switch to CPU hotplug
56 * notification.
57 */
58
59static int rtR0MpNotificationLinuxOnline(unsigned int cpu)
60{
61 RTCPUID idCpu = RTMpCpuIdFromSetIndex(cpu);
62 rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
63 return 0;
64}
65
66static int rtR0MpNotificationLinuxOffline(unsigned int cpu)
67{
68 RTCPUID idCpu = RTMpCpuIdFromSetIndex(cpu);
69 rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
70 return 0;
71}
72
73DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
74{
75 int rc;
76 IPRT_LINUX_SAVE_EFL_AC();
77 rc = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "vboxdrv:online",
78 rtR0MpNotificationLinuxOnline, rtR0MpNotificationLinuxOffline);
79 IPRT_LINUX_RESTORE_EFL_AC();
80 /*
81 * cpuhp_setup_state_nocalls() returns a positive state number for
82 * CPUHP_AP_ONLINE_DYN or -ENOSPC if there is no free slot available
83 * (see cpuhp_reserve_state / definition of CPUHP_AP_ONLINE_DYN).
84 */
85 AssertMsgReturn(rc > 0, ("%d\n", rc), RTErrConvertFromErrno(rc));
86 g_rtR0MpOnline = rc;
87 return VINF_SUCCESS;
88}
89
90
91DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
92{
93 IPRT_LINUX_SAVE_EFL_AC();
94 cpuhp_remove_state_nocalls(g_rtR0MpOnline);
95 IPRT_LINUX_RESTORE_EFL_AC();
96}
97
98#elif RTLNX_VER_MIN(2,5,71) && defined(CONFIG_SMP)
99
100static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu);
101
102/**
103 * The notifier block we use for registering the callback.
104 */
105static struct notifier_block g_NotifierBlock =
106{
107 .notifier_call = rtMpNotificationLinuxCallback,
108 .next = NULL,
109 .priority = 0
110};
111
112# ifdef CPU_DOWN_FAILED
113/**
114 * The set of CPUs we've seen going offline recently.
115 */
116static RTCPUSET g_MpPendingOfflineSet;
117# endif
118
119
120/**
121 * The native callback.
122 *
123 * @returns NOTIFY_DONE.
124 * @param pNotifierBlock Pointer to g_NotifierBlock.
125 * @param ulNativeEvent The native event.
126 * @param pvCpu The cpu id cast into a pointer value.
127 *
128 * @remarks This can fire with preemption enabled and on any CPU.
129 */
130static int rtMpNotificationLinuxCallback(struct notifier_block *pNotifierBlock, unsigned long ulNativeEvent, void *pvCpu)
131{
132 bool fProcessEvent = false;
133 RTCPUID idCpu = (uintptr_t)pvCpu;
134 NOREF(pNotifierBlock);
135
136 /*
137 * Note that redhat/CentOS ported _some_ of the FROZEN macros
138 * back to their 2.6.18-92.1.10.el5 kernel but actually don't
139 * use them. Thus we have to test for both CPU_TASKS_FROZEN and
140 * the individual event variants.
141 */
142 switch (ulNativeEvent)
143 {
144 /*
145 * Pick up online events or failures to go offline.
146 * Ignore failure events for CPUs we didn't see go offline.
147 */
148# ifdef CPU_DOWN_FAILED
149 case CPU_DOWN_FAILED:
150# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
151 case CPU_DOWN_FAILED_FROZEN:
152# endif
153 if (!RTCpuSetIsMember(&g_MpPendingOfflineSet, idCpu))
154 break; /* fProcessEvents = false */
155 /* fall thru */
156# endif
157 case CPU_ONLINE:
158# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
159 case CPU_ONLINE_FROZEN:
160# endif
161# ifdef CPU_DOWN_FAILED
162 RTCpuSetDel(&g_MpPendingOfflineSet, idCpu);
163# endif
164 fProcessEvent = true;
165 break;
166
167 /*
168 * Pick the earliest possible offline event.
169 * The only important thing here is that we get the event and that
170 * it's exactly one.
171 */
172# ifdef CPU_DOWN_PREPARE
173 case CPU_DOWN_PREPARE:
174# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
175 case CPU_DOWN_PREPARE_FROZEN:
176# endif
177 fProcessEvent = true;
178# else
179 case CPU_DEAD:
180# if defined(CPU_TASKS_FROZEN) && defined(CPU_DEAD_FROZEN)
181 case CPU_DEAD_FROZEN:
182# endif
183 /* Don't process CPU_DEAD notifications. */
184# endif
185# ifdef CPU_DOWN_FAILED
186 RTCpuSetAdd(&g_MpPendingOfflineSet, idCpu);
187# endif
188 break;
189 }
190
191 if (!fProcessEvent)
192 return NOTIFY_DONE;
193
194 switch (ulNativeEvent)
195 {
196# ifdef CPU_DOWN_FAILED
197 case CPU_DOWN_FAILED:
198# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_FAILED_FROZEN)
199 case CPU_DOWN_FAILED_FROZEN:
200# endif
201# endif
202 case CPU_ONLINE:
203# if defined(CPU_TASKS_FROZEN) && defined(CPU_ONLINE_FROZEN)
204 case CPU_ONLINE_FROZEN:
205# endif
206 rtMpNotificationDoCallbacks(RTMPEVENT_ONLINE, idCpu);
207 break;
208
209# ifdef CPU_DOWN_PREPARE
210 case CPU_DOWN_PREPARE:
211# if defined(CPU_TASKS_FROZEN) && defined(CPU_DOWN_PREPARE_FROZEN)
212 case CPU_DOWN_PREPARE_FROZEN:
213# endif
214 rtMpNotificationDoCallbacks(RTMPEVENT_OFFLINE, idCpu);
215 break;
216# endif
217 }
218
219 return NOTIFY_DONE;
220}
221
222
223DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
224{
225 int rc;
226 IPRT_LINUX_SAVE_EFL_AC();
227
228# ifdef CPU_DOWN_FAILED
229 RTCpuSetEmpty(&g_MpPendingOfflineSet);
230# endif
231
232 rc = register_cpu_notifier(&g_NotifierBlock);
233 IPRT_LINUX_RESTORE_EFL_AC();
234 AssertMsgReturn(!rc, ("%d\n", rc), RTErrConvertFromErrno(rc));
235 return VINF_SUCCESS;
236}
237
238
239DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
240{
241 IPRT_LINUX_SAVE_EFL_AC();
242 unregister_cpu_notifier(&g_NotifierBlock);
243 IPRT_LINUX_RESTORE_EFL_AC();
244}
245
246#else /* Not supported / Not needed */
247
248DECLHIDDEN(int) rtR0MpNotificationNativeInit(void)
249{
250 return VINF_SUCCESS;
251}
252
253DECLHIDDEN(void) rtR0MpNotificationNativeTerm(void)
254{
255}
256
257#endif /* Not supported / Not needed */
258
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette