VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c@ 37826

Last change on this file since 37826 was 37672, checked in by vboxsync, 13 years ago

warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/* $Id: mp-r0drv-linux.c 37672 2011-06-28 19:48:17Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
8 *
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.
16 *
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.
22 *
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.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "the-linux-kernel.h"
32#include "internal/iprt.h"
33
34#include <iprt/mp.h>
35#include <iprt/cpuset.h>
36#include <iprt/err.h>
37#include <iprt/asm.h>
38#include <iprt/thread.h>
39#include "r0drv/mp-r0drv.h"
40
41
42RTDECL(RTCPUID) RTMpCpuId(void)
43{
44 return smp_processor_id();
45}
46RT_EXPORT_SYMBOL(RTMpCpuId);
47
48
49RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
50{
51 return idCpu < RTCPUSET_MAX_CPUS && idCpu < NR_CPUS ? (int)idCpu : -1;
52}
53RT_EXPORT_SYMBOL(RTMpCpuIdToSetIndex);
54
55
56RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
57{
58 return iCpu < NR_CPUS ? (RTCPUID)iCpu : NIL_RTCPUID;
59}
60RT_EXPORT_SYMBOL(RTMpCpuIdFromSetIndex);
61
62
63RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
64{
65 return NR_CPUS - 1; //???
66}
67RT_EXPORT_SYMBOL(RTMpGetMaxCpuId);
68
69
70RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
71{
72#if defined(CONFIG_SMP)
73 if (RT_UNLIKELY(idCpu >= NR_CPUS))
74 return false;
75
76# if defined(cpu_possible)
77 return cpu_possible(idCpu);
78# else /* < 2.5.29 */
79 return idCpu < (RTCPUID)smp_num_cpus;
80# endif
81#else
82 return idCpu == RTMpCpuId();
83#endif
84}
85RT_EXPORT_SYMBOL(RTMpIsCpuPossible);
86
87
88RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
89{
90 RTCPUID idCpu;
91
92 RTCpuSetEmpty(pSet);
93 idCpu = RTMpGetMaxCpuId();
94 do
95 {
96 if (RTMpIsCpuPossible(idCpu))
97 RTCpuSetAdd(pSet, idCpu);
98 } while (idCpu-- > 0);
99 return pSet;
100}
101RT_EXPORT_SYMBOL(RTMpGetSet);
102
103
104RTDECL(RTCPUID) RTMpGetCount(void)
105{
106#ifdef CONFIG_SMP
107# if defined(CONFIG_HOTPLUG_CPU) /* introduced & uses cpu_present */
108 return num_present_cpus();
109# elif defined(num_possible_cpus)
110 return num_possible_cpus();
111# elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
112 return smp_num_cpus;
113# else
114 RTCPUSET Set;
115 RTMpGetSet(&Set);
116 return RTCpuSetCount(&Set);
117# endif
118#else
119 return 1;
120#endif
121}
122RT_EXPORT_SYMBOL(RTMpGetCount);
123
124
125RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
126{
127#ifdef CONFIG_SMP
128 if (RT_UNLIKELY(idCpu >= NR_CPUS))
129 return false;
130# ifdef cpu_online
131 return cpu_online(idCpu);
132# else /* 2.4: */
133 return cpu_online_map & RT_BIT_64(idCpu);
134# endif
135#else
136 return idCpu == RTMpCpuId();
137#endif
138}
139RT_EXPORT_SYMBOL(RTMpIsCpuOnline);
140
141
142RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
143{
144#ifdef CONFIG_SMP
145 RTCPUID idCpu;
146
147 RTCpuSetEmpty(pSet);
148 idCpu = RTMpGetMaxCpuId();
149 do
150 {
151 if (RTMpIsCpuOnline(idCpu))
152 RTCpuSetAdd(pSet, idCpu);
153 } while (idCpu-- > 0);
154#else
155 RTCpuSetEmpty(pSet);
156 RTCpuSetAdd(pSet, RTMpCpuId());
157#endif
158 return pSet;
159}
160RT_EXPORT_SYMBOL(RTMpGetOnlineSet);
161
162
163RTDECL(RTCPUID) RTMpGetOnlineCount(void)
164{
165#ifdef CONFIG_SMP
166# if defined(num_online_cpus)
167 return num_online_cpus();
168# else
169 RTCPUSET Set;
170 RTMpGetOnlineSet(&Set);
171 return RTCpuSetCount(&Set);
172# endif
173#else
174 return 1;
175#endif
176}
177RT_EXPORT_SYMBOL(RTMpGetOnlineCount);
178
179
180RTDECL(bool) RTMpIsCpuWorkPending(void)
181{
182 /** @todo (not used on non-Windows platforms yet). */
183 return false;
184}
185RT_EXPORT_SYMBOL(RTMpIsCpuWorkPending);
186
187
188/**
189 * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER
190 *
191 * @param pvInfo Pointer to the RTMPARGS package.
192 */
193static void rtmpLinuxWrapper(void *pvInfo)
194{
195 PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
196 ASMAtomicIncU32(&pArgs->cHits);
197 pArgs->pfnWorker(RTMpCpuId(), pArgs->pvUser1, pArgs->pvUser2);
198}
199
200
201RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
202{
203 int rc;
204 RTMPARGS Args;
205
206#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
207 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
208#endif
209 Args.pfnWorker = pfnWorker;
210 Args.pvUser1 = pvUser1;
211 Args.pvUser2 = pvUser2;
212 Args.idCpu = NIL_RTCPUID;
213 Args.cHits = 0;
214
215#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
216 rc = on_each_cpu(rtmpLinuxWrapper, &Args, 1 /* wait */);
217#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
218 rc = on_each_cpu(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
219#else /* older kernels */
220 RTThreadPreemptDisable(&PreemptState);
221 rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
222 local_irq_disable();
223 rtmpLinuxWrapper(&Args);
224 local_irq_enable();
225 RTThreadPreemptRestore(&PreemptState);
226#endif /* older kernels */
227 Assert(rc == 0); NOREF(rc);
228 return VINF_SUCCESS;
229}
230RT_EXPORT_SYMBOL(RTMpOnAll);
231
232
233RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
234{
235 int rc;
236 RTMPARGS Args;
237
238 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
239 Args.pfnWorker = pfnWorker;
240 Args.pvUser1 = pvUser1;
241 Args.pvUser2 = pvUser2;
242 Args.idCpu = NIL_RTCPUID;
243 Args.cHits = 0;
244
245 RTThreadPreemptDisable(&PreemptState);
246#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
247 rc = smp_call_function(rtmpLinuxWrapper, &Args, 1 /* wait */);
248#else /* older kernels */
249 rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
250#endif /* older kernels */
251 RTThreadPreemptRestore(&PreemptState);
252
253 Assert(rc == 0); NOREF(rc);
254 return VINF_SUCCESS;
255}
256RT_EXPORT_SYMBOL(RTMpOnOthers);
257
258
259#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
260/**
261 * Wrapper between the native linux per-cpu callbacks and PFNRTWORKER
262 * employed by RTMpOnSpecific on older kernels that lacks smp_call_function_single.
263 *
264 * @param pvInfo Pointer to the RTMPARGS package.
265 */
266static void rtmpOnSpecificLinuxWrapper(void *pvInfo)
267{
268 PRTMPARGS pArgs = (PRTMPARGS)pvInfo;
269 RTCPUID idCpu = RTMpCpuId();
270
271 if (idCpu == pArgs->idCpu)
272 {
273 pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
274 ASMAtomicIncU32(&pArgs->cHits);
275 }
276}
277#endif
278
279
280RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
281{
282 int rc;
283 RTMPARGS Args;
284
285 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
286 Args.pfnWorker = pfnWorker;
287 Args.pvUser1 = pvUser1;
288 Args.pvUser2 = pvUser2;
289 Args.idCpu = idCpu;
290 Args.cHits = 0;
291
292 if (!RTMpIsCpuPossible(idCpu))
293 return VERR_CPU_NOT_FOUND;
294
295 RTThreadPreemptDisable(&PreemptState);
296 if (idCpu != RTMpCpuId())
297 {
298 if (RTMpIsCpuOnline(idCpu))
299 {
300#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
301 rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 1 /* wait */);
302#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
303 rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
304#else /* older kernels */
305 rc = smp_call_function(rtmpOnSpecificLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */);
306#endif /* older kernels */
307 Assert(rc == 0);
308 rc = Args.cHits ? VINF_SUCCESS : VERR_CPU_OFFLINE;
309 }
310 else
311 rc = VERR_CPU_OFFLINE;
312 }
313 else
314 {
315 rtmpLinuxWrapper(&Args);
316 rc = VINF_SUCCESS;
317 }
318 RTThreadPreemptRestore(&PreemptState);;
319
320 NOREF(rc);
321 return rc;
322}
323RT_EXPORT_SYMBOL(RTMpOnSpecific);
324
325
326#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
327/**
328 * Dummy callback used by RTMpPokeCpu.
329 *
330 * @param pvInfo Ignored.
331 */
332static void rtmpLinuxPokeCpuCallback(void *pvInfo)
333{
334 NOREF(pvInfo);
335}
336#endif
337
338
339RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
340{
341#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
342 int rc;
343
344 if (!RTMpIsCpuPossible(idCpu))
345 return VERR_CPU_NOT_FOUND;
346 if (!RTMpIsCpuOnline(idCpu))
347 return VERR_CPU_OFFLINE;
348
349# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
350 rc = smp_call_function_single(idCpu, rtmpLinuxPokeCpuCallback, NULL, 0 /* wait */);
351# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
352 rc = smp_call_function_single(idCpu, rtmpLinuxPokeCpuCallback, NULL, 0 /* retry */, 0 /* wait */);
353# else /* older kernels */
354# error oops
355# endif /* older kernels */
356 NOREF(rc);
357 Assert(rc == 0);
358 return VINF_SUCCESS;
359
360#else /* older kernels */
361 /* no unicast here? */
362 return VERR_NOT_SUPPORTED;
363#endif /* older kernels */
364}
365RT_EXPORT_SYMBOL(RTMpPokeCpu);
366
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